1. 程式人生 > >資料結構學習(二)——單鏈表的操作之頭插法和尾插法建立連結串列

資料結構學習(二)——單鏈表的操作之頭插法和尾插法建立連結串列

連結串列也是線性表的一種,與順序表不同的是,它在記憶體中不是連續存放的。在C語言中,連結串列是通過指標相關實現的。而單鏈表是連結串列的其中一種,關於單鏈表就是其節點中有資料域和只有一個指向下個節點的指標域。建立單鏈表的方法有兩種,分別是頭插法和尾插法。

所謂頭插法,就是按節點的逆序方法逐漸將結點插入到連結串列的頭部。反之尾插法就是按節點的順序逐漸將節點插入到連結串列的尾部。相對來說,頭插法要比尾插法演算法簡單,但是最後產生的連結串列是逆序的,即第一個輸入的節點實際是連結串列的最後一個節點。而為了習慣,通常用尾插法來建立連結串列。下面的程式碼就是實現了頭插法和尾插法。程式碼在Linux下除錯通過。

#include <stdio.h>
#include <stdlib.h>

typedef struct link
{
	char data;
	struct link *next;
}linklist;

linklist *CreateList_Front();	//頭插法建立單鏈表
linklist *CreateList_End();		//尾插法建立單鏈表
void ShowLinklist(linklist *h); //輸出顯示連結串列

int main(void)
{
	int choice;
	linklist *head;

	//head = (linklist*)malloc(sizeof(linklist));
	while(1)
	{
		printf("單鏈表的建立\n");
		printf("1.使用頭插法建立單鏈表\n");
		printf("2.使用尾插法建立單鏈表\n");
		printf("3.連結串列輸出顯示\n");
		printf("4.退出\n");
		printf("做出選擇:\n");
		scanf("%d",&choice);
		switch(choice)
		{
		//頭插法
		case 1:
			head = CreateList_Front();
			break;
		//尾插法
		case 2:
			head = CreateList_End();
			break;
		//輸出連結串列
		case 3:
			ShowLinklist(head);
			break;
		//退出程式
		case 4:
			return 0;
			break;
		default:
			break;
		}
	}
	return 1;
}

linklist *CreateList_Front()
{
	linklist *head, *p;
	char ch;

	head = NULL;
	printf("依次輸入字元資料(‘#’表示輸入結束):\n");
	ch = getchar();
	while(ch != '#')
	{
		p = (linklist*)malloc(sizeof(linklist));
		p->data = ch;
		p->next = head;
		head = p;
		ch = getchar();				//頭插法演算法簡單 核心就兩句p->next = head;head = p;
	}
	return head;
}

linklist *CreateList_End()
{
	linklist *head, *p, *e;
	char ch;

	head = NULL;
	e = NULL;
	printf("請依次輸入字元資料('#'表示輸入結束):\n");
	ch = getchar();
	while(ch != '#')
	{
		p = (linklist*)malloc(sizeof(linklist));
		p->data = ch;
		if(head == NULL)		//先判斷輸入的是不是第一個節點
		{
			head = p;			
		}
		else
		{
			e->next = p;		//e始終指向輸入的最後一個節點
		}
		e = p;
		ch = getchar();			
	}
	if(e != NULL)				//如果連結串列不為空,則最後節點的下一個節點為空
	{
		e->next = NULL;
	}
	return head;				//尾插法比頭插法複雜一些,程式中要做兩次判斷,分別是判斷第一個節點和最後一個節點的判斷。且消耗多一個指標變數e。
}

void ShowLinklist(linklist *h)
{
	linklist *p;

	p = h;
	while(p != NULL)
	{
		printf("%c ", p->data);
		p = p->next;
	}
	printf("\n");
}

通過上述程式碼可以看出,尾插法確實比頭插法複雜點,多了兩個判斷。但是這是可以解決的,通過新增一個頭節點,此節點不存放資料域,只是存放指向下個節點的指標域就是了。這樣就可以免除掉兩次判斷。整體也要清晰點了。下面是增加一個頭節點後尾插法的實現程式碼:

#include <stdio.h>
#include <stdlib.h>

typedef struct list
{
	char data;
	struct list *next;
}linklist;

linklist *CreateList_End();		//尾插法建立連結串列
void ShowLinklist(linklist *h);	//輸出顯示連結串列

int main(void)
{
	linklist *head;

	printf("使用尾插法建立連結串列(改進版)\n");
	printf("請依次輸入字元資料(‘#’表示輸入結束):\n");
	head = CreateList_End();		//建立連結串列
	ShowLinklist(head);				//輸出連結串列
}

linklist *CreateList_End()
{
	linklist *head, *p, *e;
	char ch;

	head = (linklist*)malloc(sizeof(linklist));
	e = head;			//讓e指向頭節點
	ch = getchar();
	while(ch != '#')
	{
		p = (linklist*)malloc(sizeof(linklist));
		p->data = ch; 
		e->next = p;		//把新節點新增到表尾
		e = p;				//把指標指向新節點
		ch = getchar();
	}	
	e->next = NULL;			//尾節點的指標域置空
	return head;
}

void ShowLinklist(linklist *h)
{
	linklist *p;

	p = h->next;
	while(p != NULL)
	{
		printf("%c ", p->data);
		p = p->next;
	}
	printf("\n");
}

添加了一個頭節點後代碼是不是就要清晰點了呢?