上次學習了單向鏈表的相關內容。此次主要研究一下雙向鏈表。node
在單向鏈表中,每次找到一個結點,都要經歷一個循環。若是在找到當前結點後,想要找到前面的結點,還要從新進行一次循環。markdown
而雙向鏈表中,是在單向鏈表的基礎上,增長了一個指向前一個結點的指針。這樣,經過空間換時間的方式,在不少操做中,會大幅的提升操做鏈表的效率。數據結構
下面咱們開始具體聊聊雙向鏈表。post
上篇文章單向鏈表,沒有介紹相關鏈表的概念。我的感受,單向的比較簡單。但在雙向鏈表上,前面已經提到了,新增了指向錢一個結點的指針,操做起來要比單向鏈表複雜了一些,尤爲在雙向循環鏈表中,若是頭腦中沒有一個相對來講的圖形概念,很容易把本身繞暈。我在這篇文章把相關的概念補充補充。學習
單向量表結點包含兩個域:數據域和指針域spa
與單向鏈表結點相比,多了一個指針域。也就是說,它有一個數據域和兩個指針域。下面圖片中data是數據域,指針域next和prior,分別指向後面結點的地址前面結點的地址。 指針
單向鏈表是按照前一個結點指向後一個結點的方式,依次將結點鏈接起來的一種表現形式。code
在這些結點中,能夠再進行一下細分爲:首元結點,中間結點和尾結點。如此細分的緣由:當進行鏈表操做時(插入、刪除、改、查),不一樣類型的結點處理方式不一樣。好比插入一個結點到單向量表中,插入的結點用node表示:orm
文字有點蒼白,仍是圖來的直觀點圖片
和單向鏈表相比,雙向鏈表的結點中多了一個指向前結點的指針域。直接看圖,比較直觀一些
雙向循環鏈表經過前面的概念,看看圖也是很好理解的。
在首元結點以前增長一個頭結點,用來指向鏈表起始點。
p.s. 不信?你能夠本身寫寫不帶頭結點的鏈表增刪改查,你就知道有多噁心了!!!
單向鏈表相關代碼實現,請參考上篇文章20200401-數據結構-單向鏈表
我多說了,開始上代碼。如下代碼的主要目錄流程
準備代碼
#define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0 typedef int ElemType; typedef int Status; typedef struct Node * LinkList; typedef struct Node{ ElemType data; LinkList prior; LinkList next; }Node; 複製代碼
初始化
Status createList(LinkList *list, int length) { *list = (LinkList)malloc(sizeof(Node)); if (!*list) { return ERROR; } LinkList p = *list; p->data = -1; p->prior = NULL; p->next = NULL; for (int i = 1; i <= length; i++) { LinkList node = (LinkList)malloc(sizeof(Node)); if (!node) { return ERROR; } node->data = i; node->prior = NULL; node->next = NULL; p->next = node; node->prior = p; p = p->next; } return OK; } 複製代碼
打印鏈表
Status displayList(LinkList list) { if (list == NULL) { printf("空鏈表不打印"); return ERROR; } LinkList p = list->next; while (p) { printf("%5d", p->data); p = p->next; } printf("\n"); return OK; } 複製代碼
增長元素
Status insertNode(LinkList *list, int pos, ElemType value) { if (pos < 1) { return ERROR; } if ((*list)->next == NULL) { return ERROR; } LinkList p = (*list); int i; for (i = 1; i < pos && p; i++) { p = p->next; } if (p == NULL) { printf("插入位置大於鏈表長度\n"); return ERROR; } LinkList node = (LinkList)malloc(sizeof(Node)); if (!node) { return ERROR; } node->data = value; node->prior = NULL; node->next = NULL; if (p->next == NULL) { p->next = node; node->prior = p; } else { p->next->prior = node; node->next = p->next; node->prior = p; p->next = node; } return OK; } 複製代碼
刪除元素
//根據指定位置 刪除結點 Status listDelPos(LinkList *list, int pos, ElemType *delData) { if (pos < 1) { return ERROR; } LinkList p = *list; if (p->next == NULL) { return ERROR; } int i; for (i = 1; i <= pos && p; i++) { p = p->next; } if (!p) { return ERROR; } *delData = p->data; if (p->next == NULL) { p->prior->next = NULL; } else { p->prior->next = p->next; p->next->prior = p->prior; } free(p); return OK; } //根據value 刪除結點 Status listDelVal(LinkList *list, ElemType value) { LinkList p = *list; int ret = ERROR; while (p->next) { p = p->next; if (value == p->data) { p->prior->next = p->next; if (p->next) { p->next->prior = p->prior; } ret = OK; break; } } return ret; } 複製代碼
修改元素
Status updateListIndexNode(LinkList *list, int index, ElemType elem) { LinkList p = (*list)->next; for (int i = 1; i < index && p; i++) { p = p->next; } if (p) { p->data = elem; } else { return ERROR; } return OK; } 複製代碼
查找元素
int listSelectElem(LinkList list, ElemType elem) { int index = 1; LinkList p = list->next; while (p) { if (p->data == elem) { return index; } p = p->next; index++; } return -1; } 複製代碼
初始化
Status createList(LinkList *list) { *list = (LinkList)malloc(sizeof(Node)); if (!*list) { return ERROR; } LinkList p = *list; p->data = -1; p->prior = NULL; p->next = NULL; for (int i = 1; i <= 5; i++) { LinkList node = (LinkList)malloc(sizeof(Node)); if (!node) { return ERROR; } node->data = i; node->next = *list; node->prior = p; p->next = node; (*list)->prior = node; p = p->next; } return OK; } 複製代碼
打印鏈表
Status displayList(LinkList list) { if (list == NULL) { return ERROR; } LinkList p = list->next; while (p != list) { printf("%5d", p->data); p = p->next; } printf("\n"); return OK; } 複製代碼
增長元素
Status insertValue(LinkList *list, int pos, ElemType value) { LinkList p = *list; if (p == NULL) { return ERROR; } int i = 1; while (i < pos && p->next != *list) { p = p->next; i++; } if (i > pos) { return ERROR; } LinkList node = (LinkList)malloc(sizeof(Node)); if (node == NULL) { return ERROR; } node->data = value; node->prior = p; node->next = p->next; node->next->prior = node; p->next = node; return OK; } 複製代碼
刪除元素
Status delValue(LinkList *list, int pos, ElemType *e) { if (*list == NULL) { return ERROR; } LinkList p = (*list)->next; int i = 1; while (i < pos && p->next != *list) { p = p->next; i++; } if (i != pos && p->next == *list) { printf("要刪除的位置大於鏈表的長度"); return ERROR; } *e = p->data; p->next->prior = p->prior; p->prior->next = p->next; free(p); if ((*list)->next == NULL) { free(*list); *list = NULL; return OK; } return OK; } 複製代碼
以上代碼能夠有些邊界值考慮不周到的地方,你們根據具體需求進行修改吧。鏈表的操做不要去背代碼,而要去理解。想不通的地方,能夠在紙上多畫畫。本人博客新手,有很差的地方,還請你們指出,我會學着去修改。
謝謝!!!
仍是用那句話收尾:沿途的風景要比目的地更彎的否!!!