1. 程式人生 > >資料結構中單鏈表的實現+單鏈表的C語言實現原始碼

資料結構中單鏈表的實現+單鏈表的C語言實現原始碼

線性表(List):零個或多個數據元素的有限序列。線性表的抽象資料型別。

線性表的順序儲存:

優點:無須為表示表中元素的邏輯關係而額外的儲存空間,可以快速的取表中任意位置的元素。

缺點:插入和刪除操作需要轉移大量元素,線性表的長度較大時,難以確定儲存空間的容量, 造成儲存空間的“碎片”。

線性表的鏈式儲存:

為了表示每一個數據元素a1與其直接後級資料元素ai+1之間的邏輯關係,對資料元素a1來說,除了儲存其本身的資訊之外,還需儲存一個指示其直接後繼的訊號(即直接後繼的儲存位置)。儲存資料元素資訊的域叫做資料域,把儲存直接後繼位置的域稱為指標域。指標域中儲存的資訊稱為指標或鏈。這兩部分組成資料元素ai

的儲存影像,稱為結點(Node

其中頭指標和頭結點的區別:

1,頭指標是指向連結串列的第一個結點的指標,若連結串列有都結點,則指向頭結點的指標。頭指標具有標示作用,所以常用頭指標冠以連結串列的名字。無論連結串列是否為空,頭指標均不為空,頭指標是連結串列的必要條件。

2,頭結點是為了操作的統一和方便設定的,放在頭一個元素的結點之前,其資料域一般無意義。有了頭結點,對其在第一元素位置前插入刪除擦偶偶與其他結點的操作統一。頭結點不是連結串列的必須要素。

帶有頭結點的指標;

空連結串列:

C語言中用結構指標表示結點:

typedef struct Node
{	
	int data;
	struct Node *next;
}Node, *pNode,*LinkList;

其中單鏈表的抽象資料結構即操作有:

void InitList(LinkList *list);//初始化操作,建立空的單鏈表
void ClearList(LinkList *list);//清空單鏈表。

void ListInsert(LinkList *list,int i, int e);//單鏈表第i個位置後面插入變數e
void DestoryList(LinkList *list);//銷燬連結串列
bool ListEmpty(LinkList list);//判斷單鏈表是否為空,為空返回真
void GetElem(LinkList, int &e, int i);//將單鏈表中第i個位置的值返回給變數e
void ListDelete(LinkList *list, int i, int &e);//刪除單鏈表表第i個位置元素
void ListTraverse(LinkList list);//遍歷線性表
int ListLength(LinkList list);//返回線性表的長度
void Recursion(LinkList list);//遞迴逆序輸出單鏈表

各種函式的實現原始碼:

void InitList(LinkList *list)
{
	*list = (LinkList)malloc(sizeof(Node));
	(*list)->next = NULL;
	(*list)->data = 0;
}
void ListInsert(LinkList *list, int i , int e)//第i個元素後面插入e
{	
	LinkList p = *list;
	
	if( i == 0)
		{
			pNode q = (LinkList)malloc(sizeof(Node));
			q->next = NULL;
			q->data = e;
			p->next = q;
		}
	else
		{	
			pNode p = (*list)->next;
			int j = 1;

			while( p && i > j)
			{
				p = p->next;
				++j;
			}

			pNode q = (LinkList)malloc(sizeof(Node));
			q->next = p->next;
			q->data = e;
			p->next = q;
		}
	
}
void ListTraverse(LinkList list)
{
	pNode p = list;
	if(p != NULL)
	{
		p = p->next;
	}	
	else 	
	{
		return;
	}
	while(p)
	{
		printf("%d\t", p->data);
		p = p->next;
	}
}
void Recursion(LinkList list)//遞迴的方法逆序輸出連結串列
{ 
	if(NULL==list)
	{ 
		return;
	} 
	if(list->next!=NULL)
	{
	 Recursion(list->next);
	 }
	printf("%d\t",list->data);
}
bool ListEmpty(LinkList list)
{
	pNode p = list;

	if(NULL == list->next)
		return true;
	else
		return false;
}
void GetElem(LinkList list, int &e, int i)
{
	pNode p = list;
	
	if( i < 0 || i > ListLength(list))
		return ;
	p = p->next;
	int j = 1;
	while( j < i)
		{
			p = p->next;
			j++;
		}
	e = p->data;
}
void ListDelete(LinkList *list, int i, int &e)
{
	pNode p = *list;
	if( i < 0 || i > ListLength(*list))
		return ;
	pNode q = p;
	p = q->next;
	int j = 1;
	while( j < i )
		{	q = p;
			p = p->next;
			j++;
		}
	p->data = e;
	q->next = p->next;
	free(p);
	

	
}
int ListLength(LinkList list)
{
	pNode p = list;
	int i = 0;
	p = p->next;
	while(p)
		{
			p = p->next;
			i++;
		}
	return i;
}
void ClearList (LinkList *list)
{
	pNode p = *list;
	if( p != NULL)
		p = p->next;
	pNode q;
	while( p )
	{
		q = p;
		p = p->next;
		free(q);
	}
	
}
void DestoryList(LinkList *list)
{
	pNode p = *list;
	if( p != NULL)
		p = p->next;
	pNode q;
	while( p )
	{
		q = p;
		p = p->next;
		free(q);
	}
	free(*list);
}

測試函式原始碼:

int main()
{
	LinkList list;

	InitList(&list);
	
	ListInsert(&list, 0, 1);
	ListInsert(&list, 1, 2);
	ListInsert(&list, 2, 3);
	ListInsert(&list, 1, 4);
	ListInsert(&list, 1, 5);
	ListInsert(&list, 5, 6);
	ListInsert(&list, 6, 7);
	ListInsert(&list, 7, 8);
	ListInsert(&list, 8, 9);
	ListInsert(&list, 9, 10);

	printf("\n遞迴呼叫函式Reversion:\n");
	LinkList p = list->next;
	Recursion(p);

	printf("\n遍歷連結串列ListTranverse:\n");
	ListTraverse(list);


	int j = ListLength(list);
	printf("\n連結串列的長度ListLength:%d\t",j);

	int e;
	GetElem(list, e,  3);
	printf("取連結串列特定的元素GetElem : %d\n",e);

	ListDelete(&list, 1, e);
	printf("\n刪除連結串列中特定位置的元素:%d\n", e);
	ListTraverse(list);

	ClearList (&list);
	printf("\n連結串列清空ClearList: \n");
	ListInsert(&list, 0, 1);
	ListInsert(&list, 1, 2);
	ListInsert(&list, 2, 3);
	ListTraverse(list);


	DestoryList(&list);

	return 0;
}


參考: 大話資料結構,資料結構(C語言版)嚴蔚敏版