线性表(二)——链表
文章目錄
- 鏈表(Linked Table)
- 1.單鏈表(singly linked list)
- 元素的構(gòu)成
- 鏈表的基本操作
- 鏈表的創(chuàng)建
- 遍歷操作
- 查找操作
- 插入操作
- 刪除操作
鏈表(Linked Table)
線性表的鏈?zhǔn)酱鎯?chǔ)結(jié)構(gòu)生成的表,稱作“鏈表”。
鏈表分為單向鏈表和雙向鏈表。
1.單鏈表(singly linked list)
單鏈表(singly linked list)是用一組任意的存儲(chǔ)單元存放的線性表元素,這組存儲(chǔ)單元可以連續(xù)也可以不連續(xù),甚至可以零散分布在內(nèi)存中的任意位置。為了能夠體現(xiàn)出數(shù)據(jù)元素之間的邏輯關(guān)系,每個(gè)存儲(chǔ)單元在在存儲(chǔ)數(shù)據(jù)元素的同時(shí),還必須存儲(chǔ)其后繼元素所在的地址信息,這個(gè)地址信息稱為指針,這兩部分組成了數(shù)據(jù)元素的存儲(chǔ)映像,稱為結(jié)點(diǎn)(node)。
鏈表的簡(jiǎn)單原理圖如圖:
結(jié)點(diǎn)結(jié)構(gòu)如圖所示:
元素的構(gòu)成
每個(gè)元素本身由兩部分組成:
單鏈表正是通過每個(gè)結(jié)點(diǎn)的指針域?qū)⒕€性表的數(shù)據(jù)元素按其邏輯次序鏈接在一起,由于每個(gè)結(jié)點(diǎn)只有一個(gè)指針域,故稱為單鏈表。
單鏈表中每個(gè)結(jié)點(diǎn)的存儲(chǔ)地址存放在其前驅(qū)結(jié)點(diǎn)的next域中,而第一個(gè)元素?zé)o前驅(qū),所以設(shè)頭指針(head pointer)指向第一個(gè)元素所在結(jié)點(diǎn)(稱為開始結(jié)點(diǎn)),整個(gè)單鏈表的存取必須從頭指針開始進(jìn)行,因而頭指針具有標(biāo)識(shí)一個(gè)單鏈表的作用;同時(shí),由于最后一個(gè)元素?zé)o后繼,故最后一個(gè)元素所在結(jié)點(diǎn)(稱為終端結(jié)點(diǎn))的指針域?yàn)榭?#xff0c;即NULL。
指向第一個(gè)結(jié)點(diǎn)(開始結(jié)點(diǎn))的指針必須保存,否則該鏈表將會(huì)消失。通常在單鏈表的開始結(jié)點(diǎn)之前附設(shè)一個(gè)類型相同的結(jié)點(diǎn),稱為頭結(jié)點(diǎn)(head node)。加上頭結(jié)點(diǎn)之后,無(wú)論單鏈表是否為空,頭指針始終指向頭結(jié)點(diǎn)。
鏈表結(jié)點(diǎn)中包含一個(gè)指針變量,用于存放下一個(gè)Node結(jié)構(gòu)結(jié)點(diǎn)的地址,所以該指針必須是與結(jié)構(gòu)體相同的數(shù)據(jù)類型。
typedef int ElementType; struct Node {ElementType data; //ElementType是date的數(shù)據(jù)類型struct Node *Next; //指向直接后繼元素的指針 };鏈表的基本操作
在構(gòu)建鏈表時(shí),需要逐個(gè)創(chuàng)建結(jié)點(diǎn),并且把生成的每個(gè)結(jié)點(diǎn)加入到鏈表中。創(chuàng)建結(jié)點(diǎn)包括3個(gè)步驟:
鏈表的創(chuàng)建
創(chuàng)建一個(gè)僅含頭結(jié)點(diǎn)的空鏈表:
typedef struct Node *List; int iCount = 0; //記錄鏈表長(zhǎng)度的全局變量 List InitList() {struct Node *pHead = (struct Node*)malloc(sizeof(struct Node)); //為頭結(jié)點(diǎn)分配內(nèi)存空間pHead->Next = NULL;iCount = 0;return pHead; }鏈表還可以使用頭指針創(chuàng)建
List InitList() {List pHead = NULL; //頭指針為空return pHead; }遍歷操作
遍歷打印鏈表元素
void PrintList(List L) {List p = L->Next; //工作指針p初始化while(p != NULL){printf("%d\n",p->data);p = p->Next;} }求線性表長(zhǎng)度
int Length(List L) {List p = L->Next; //工作指針p初始化int count = 0; //累加器count初始化while(p != NULL){p = p->Next;count++;}return count; }查找操作
按位查找:從頭結(jié)點(diǎn)出發(fā)順Next域逐個(gè)結(jié)點(diǎn)向下搜索,當(dāng)工作指針p指向某個(gè)結(jié)點(diǎn)時(shí)判斷是否為第 i 個(gè)結(jié)點(diǎn),若是,則查找成功;否則,將工作指針后移。對(duì)每個(gè)結(jié)點(diǎn)依次執(zhí)行上述操作,知道p為NULL時(shí)查找失敗。
ElementType GetData(List L, int i) {List p = L->Next; //工作指針p初始化,指向頭結(jié)點(diǎn)后的第一個(gè)元素int count = 1; //累加器count初始化while(p != NULL && count < i){p = p->Next;count++;}if(p == NULL) {printf("The input position exceeds the length of the linked list");}elsereturn p->data; }按值查找:對(duì)鏈表中的元素依次進(jìn)行比較,如果查找成功,返回元素的序號(hào),如果查找不成功,則返回0表示查找失敗。
int Locate(List L, ElementType element) {List p = L->Next; //工作指針p初始化,指向頭結(jié)點(diǎn)后的第一個(gè)元素int count = 1; //累加器count初始化while(p != NULL){if(p->data == element)return count; //查找成功,結(jié)束函數(shù)并返回序號(hào)p = p->Next;count++;}return 0; //表示查找失敗,返回0 }插入操作
每次加入一個(gè)結(jié)點(diǎn),使用循環(huán)可創(chuàng)建一個(gè)含有n個(gè)結(jié)點(diǎn)的單鏈表
頭插法:
頭插法是每次將新申請(qǐng)的結(jié)點(diǎn)插在頭結(jié)點(diǎn)的后面,其執(zhí)行過程如圖所示。
尾插法:
尾插法就是每次將新申請(qǐng)的結(jié)點(diǎn)插在終端結(jié)點(diǎn)的后面,其執(zhí)行過程如圖所示。
void ListEndInsert(List L) {char c;List pHead = L;char flag;List pNew, pEnd;pEnd = pHead; //尾指針初始化,指向頭結(jié)點(diǎn)do{iCount++;pNew = (struct Node *)malloc(sizeof(struct Node));printf("Please enter the Number\n");scanf("%d",&pNew->data);pEnd->Next = pNew; //尾指針指向新結(jié)點(diǎn)pEnd = pNew; //pEnd指向新結(jié)點(diǎn)printf("Do you want to continue typing?(y/n)\n");while((c = getchar()) != '\n' && c != EOF);//不停地使用getchar()獲取緩沖中字符,直到獲取的c是“\n”或文件結(jié)尾符EOF為止scanf("%c",&flag);}while('y' == flag);pEnd->Next = NULL; }和前面的創(chuàng)建初始化寫在一起可以創(chuàng)建一個(gè)含N個(gè)元素的鏈表。
向鏈表中任意位置插入結(jié)點(diǎn),插入到第 i 個(gè)位置,即插入到鏈表 i-1 與 i 之間。必須先掃描鏈表找到 i-1 的存儲(chǔ)地址 p ,然后生成一個(gè)新的結(jié)點(diǎn) pNew,將 pNew 的Next域指向第 i 個(gè)結(jié)點(diǎn),將結(jié)點(diǎn) p 的Next域指向新結(jié)點(diǎn)。
void Insert(List L, int i, ElementType element) {List pNew;List p = L; //工作指針p初始化,指向頭結(jié)點(diǎn)int count = 0; //累加器count初始化while(p != NULL && count < i-1) //查找第 i-1 個(gè)結(jié)點(diǎn){p = p->Next; //工作指針后移count++;}if(p == NULL) {printf("The input position exceeds the length of the linked list");}else{pNew = (struct Node *)malloc(sizeof(struct Node));pNew->data = element;pNew->Next = p->Next;p->Next = pNew; //將新結(jié)點(diǎn)插入到結(jié)點(diǎn)p之后iCount++; //鏈表長(zhǎng)度加1} }刪除操作
將單鏈表的第 i 個(gè)結(jié)點(diǎn)刪去,首先要找到 i-1 個(gè)結(jié)點(diǎn)的存儲(chǔ)地址p,然后令p的Next域指向 i 的后繼結(jié)點(diǎn),釋放結(jié)點(diǎn) i 的存儲(chǔ)空間。被刪結(jié)點(diǎn)的的前驅(qū)結(jié)點(diǎn)p存在且不是終端結(jié)點(diǎn)時(shí),才能確定被刪結(jié)點(diǎn)存在。
void Delete(List L, int i) {List pTemp;List p = L; //工作指針p初始化,指向頭結(jié)點(diǎn)int count = 0; //累加器count初始化while(p != NULL && count < i-1) //查找第 i-1 個(gè)結(jié)點(diǎn){p = p->Next; //工作指針后移count++;}if(p == NULL || p->Next == NULL) {printf("The input position exceeds the length of the linked list");}else{pTemp = p->Next; //暫存被刪結(jié)點(diǎn)p->Next = pTemp->Next; //摘鏈free(pTemp);iCount--; //鏈表長(zhǎng)度減1} }刪除整個(gè)鏈表
void DeleteList(List L) {List p, pTemp;p = L->Next;L->Next = NULL;while(p != NULL){pTemp = p->Next;free(p);p = pTemp;iCount--;} }總結(jié)
以上是生活随笔為你收集整理的线性表(二)——链表的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java学习笔记(十一)--类与对象
- 下一篇: 线性表(一)——顺序表