【線性表】鏈表:循環單鏈表、雙鏈表、循環雙鏈表的基本特性

鏈表不僅作爲鏈式存儲的一種實現方式,還表達了計算機不連續(離散)的存儲思想在初學階段,鏈表的實現類型有單鏈表(帶/不帶頭結點)、循環單鏈表、雙鏈表、循環雙鏈表四種。

上文已經講解了單鏈表,接下來將講解其他三類。


Table of Contents

循環單鏈表

雙鏈表

循環雙鏈表


循環單鏈表

 

定義:

將單鏈表中終端結點的指針端由 NULL 改爲 指向頭結點 ,就使整個單鏈表形成一個,這種頭尾相接的單鏈表稱爲單循環鏈表,簡稱循環鏈表

 

 

兩種情形:

  • 爲使空鏈表與非空鏈表處理一致,通常設置一個頭結點。但並非必須設置頭結點。

循環單鏈表特徵:

  1. 對於單鏈表而言,最後一個結點指向NULL;把最後一個結點的不指向NULL而指向頭,就是循環單鏈表;
  2. 在單循環鏈表上的操作基本上與非循環鏈表相同。循環鏈表和單鏈表的主要差異就在於循環的條件判斷上,原來是 p->next == NULL,現在是 p->next != 頭結點 ,則循環未結束。
  3. 單循環鏈表可以從表中任意結點開始遍歷整個鏈表,不僅如此,有時對鏈表常做的操作是在表尾、表頭進行。如果頭指針表示循環鏈表,則需O(n) 時間找到最後一個結點。若改尾指針表示循環鏈表,此時查找開始結點和終端結點都很方便了查找終端結點時間是O(1),而開始結點,其實就是 rear->next->next ,其時間複雜也爲O(1)。

第一個循環單鏈表


#include <stdio.h>
#include <malloc.h>
#include <assert.h>

typedef struct node
{
	int data;
	struct node* next;
}Node; //struct node 完全等於 Node(結構體變量)
typedef Node* LinkList; //struct node * 完全等於 LinkList(結構體指針)

int main()
{
	LinkList head = (LinkList)malloc(sizeof(Node));
	assert(head != NULL);  //檢查malloc之後是不是空間不夠,返回了空指針NULL(WarningC6011:取消對NULL指針的引用)
	LinkList NodeAa = (LinkList)malloc(sizeof(Node));
	assert(NodeAa != NULL);
	LinkList NodeBb = (LinkList)malloc(sizeof(Node));
	assert(NodeBb != NULL);
	LinkList NodeCc = (LinkList)malloc(sizeof(Node));
	assert(NodeCc != NULL);

	head->data = NULL; //頭結點,不保存數據
	head->next = NodeAa;
	NodeAa->data = 202;
	NodeAa->next = NodeBb;
	NodeBb->data = 303;
	NodeBb->next = NodeCc;
	NodeCc->data = 404;
	NodeCc->next = head;  //單鏈表中:NodeCc->next = NULL;

	LinkList p = head->next; //把鏈表頭結點的下一個節點,交給指針p,去遍歷
	while (p != head)
	{
		printf("%d  ", p->data);
		p = p->next;
	}

	return 0;
}

 

 


雙鏈表

 

定義:

雙向鏈表也叫雙鏈表,它的每個數據結點中都有兩個指針(保存兩個節點的地址),分別指向直接後繼直接前驅

 

 

雙鏈表的代碼定義:

 

typedef struct node
{
	int data;
	struct node* pre; //前驅
	struct node* next; //後繼
}Node;

 

特性:

  1. 從雙向鏈表中的任意一個結點開始,都可以很方便地訪問它的前驅結點和後繼結點
  2. 循環鏈表的最後一個結點指向頭結點,循環鏈表的操作和單鏈表的操作基本一致,差別僅僅在於算法中的循環條件有所不同。
  3. 雙向鏈表使單鏈表中擴展出來的結構,因此有一部分操作與單鏈表是相同的,如求長度函數、查找元素位置、打印函數、銷燬函數等,這些函數操作都只要涉及一個方向的指針即可。

第一個雙鏈表

第一個雙鏈表
#include <stdio.h>
#include <malloc.h>
#include <assert.h>

typedef struct node
{
	int data;
	struct node* pre;
	struct node* next;
}Node; //struct node 完全等於 Node(結構體變量)
typedef Node* LinkList; //struct node * 完全等於 LinkList(結構體指針)

int main()
{
	LinkList head = (LinkList)malloc(sizeof(Node));
	assert(head != NULL);  //檢查malloc之後是不是空間不夠,返回了空指針NULL(WarningC6011:取消對NULL指針的引用)
	LinkList NodeAa = (LinkList)malloc(sizeof(Node));
	assert(NodeAa != NULL);
	LinkList NodeBb = (LinkList)malloc(sizeof(Node));
	assert(NodeBb != NULL);
	LinkList NodeCc = (LinkList)malloc(sizeof(Node));
	assert(NodeCc != NULL);

	head->data = 101;
	head->pre = NULL;
	head->next = NodeAa;

	NodeAa->data = 202;
	NodeAa->pre = head;
	NodeAa->next = NodeBb;

	NodeBb->data = 303;
	NodeBb->pre = NodeAa;
	NodeBb->next = NodeCc;

	NodeCc->data = 404;
	NodeCc->pre = NodeBb;
	NodeCc->next = NULL;  //單鏈表中:NodeCc->next = NULL;

	LinkList p = head; //把鏈表頭結點的下一個交給指針p,去遍歷
	printf("順序遍歷:");
	while (p != NULL)
	{
		printf("%d  ", p->data);
		p = p->next;
	}

	printf("\n逆序遍歷:");
	LinkList tail = NodeCc;
	p = tail;
	while (p != NULL)
	{
		printf("%d  ", p->data);
		p = p->pre;
	}

	return 0;
}

 

 


循環雙鏈表

 

定義:

雙向鏈表也叫雙鏈表,它的每個數據結點中都有兩個指針(保存兩個節點的地址),分別指向直接後繼直接前驅頭指針的前驅指向最後一個節點,最後一個節點的後繼指向頭指針。

雙鏈表的代碼定義:

typedef struct node
{
	int data;
	struct node* pre; //前驅
	struct node* next; //後繼
}Node;

特性:

  1. 從雙向鏈表中的任意一個結點開始,都可以很方便地訪問它的前驅結點和後繼結點
  2. 循環鏈表的最後一個結點指向頭結點,循環鏈表的操作和單鏈表的操作基本一致,差別僅僅在於算法中的循環條件有所不同。
  3. 雙向鏈表使單鏈表中擴展出來的結構,因此有一部分操作與單鏈表是相同的,如求長度函數、查找元素位置、打印函數、銷燬函數等,這些函數操作都只要涉及一個方向的指針即可。

兩種情形:

第一個循環雙鏈表

#include <stdio.h>
#include <malloc.h>
#include <assert.h>

typedef struct node
{
	int data;
	struct node* pre;
	struct node* next;
}Node; //struct node 完全等於 Node(結構體變量)
typedef Node* LinkList; //struct node * 完全等於 LinkList(結構體指針)

int main()
{
	LinkList head = (LinkList)malloc(sizeof(Node));
	assert(head != NULL);  //檢查malloc之後是不是空間不夠,返回了空指針NULL(WarningC6011:取消對NULL指針的引用)
	LinkList NodeAa = (LinkList)malloc(sizeof(Node));
	assert(NodeAa != NULL);
	LinkList NodeBb = (LinkList)malloc(sizeof(Node));
	assert(NodeBb != NULL);
	LinkList NodeCc = (LinkList)malloc(sizeof(Node));
	assert(NodeCc != NULL);

	head->data = NULL; //頭結點,不保存數據
	head->pre = NodeCc;
	head->next = NodeAa;

	NodeAa->data = 202;
	NodeAa->pre = head;
	NodeAa->next = NodeBb;

	NodeBb->data = 303;
	NodeBb->pre = NodeAa;
	NodeBb->next = NodeCc;

	NodeCc->data = 404;
	NodeCc->pre = NodeBb;
	NodeCc->next = head;  //單鏈表中:NodeCc->next = NULL;

	LinkList p = head->next; //把鏈表頭結點的下一個交給指針p,去遍歷
	printf("順序遍歷:");
	while (p != head)
	{
		printf("%d  ", p->data);
		p = p->next;
	}

	printf("\n逆序遍歷:");
	p = p->pre;
	while (p != head)
	{
		printf("%d  ", p->data);
		p = p->pre;
	}

	return 0;
}


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章