雙向鏈表和單向鏈表也是有很多相似的地方的,聽名字可以猜到,每個節點都包含兩個指針,一個指針指向上一個節點,一個指針指向下一個節點。這里有兩個特殊的地方,第一就是頭節點的一個指針指向NULL空指針(沒有前驅節點),第二就是尾節點的一個指針指向NULL指針(沒有后繼節點)。
#ifndef DOUBLY_LINKED_LIST_H #define DOUBLY_LINKED_LIST_H typedef struct Node { int data; struct Node *pNext; struct Node *pPre; }NODE, *pNODE; //創建雙向鏈表 pNODE CreateDbLinkList(void); //打印鏈表 void TraverseDbLinkList(pNODE pHead); //判斷鏈表是否為空 int IsEmptyDbLinkList(pNODE pHead); //計算鏈表長度 int GetLengthDbLinkList(pNODE pHead); //向鏈表插入節點 int InsertEleDbLinkList(pNODE pHead, int pos, int data); //從鏈表刪除節點 int DeleteEleDbLinkList(pNODE pHead, int pos); //刪除整個鏈表,釋放內存 void FreeMemory(pNODE *ppHead); #endif
DbLinkList.cpp 雙向鏈表的源文件——包含了各種操作函數的定義。
(1)這部分是創建雙向鏈表,和單向鏈表很相似,但是呢,有些地方還是得注意,就是每創建一個節點的時候都要注意初始化它的兩個指針。
#include <stdio.h> #include <stdlib.h> #include "DbLinkList.h" //創建雙向鏈表 pNODE CreateDbLinkList(void) { int i, length = 0, data = 0; pNODE pTail = NULL, p_new = NULL; pNODE pHead = (pNODE)malloc(sizeof(NODE)); if (NULL == pHead) { printf("內存分配失敗!\n"); exit(EXIT_FAILURE); } pHead->data = 0; pHead->pPre = NULL; pHead->pNext = NULL; pTail = pHead; printf("請輸入想要創建鏈表的長度:"); scanf("%d", &length); for (i=1; i<length+1; i++) { p_new = (pNODE)malloc(sizeof(NODE)); if (NULL == p_new) { printf("內存分配失敗!\n"); exit(EXIT_FAILURE); } printf("請輸入第%d個元素的值:", i); scanf("%d", &data); p_new->data = data; p_new->pNext = NULL; p_new->pPre = pTail; pTail->pNext = p_new; pTail = p_new; } return pHead; }
(2)這部分是獲得雙向鏈表的信息,這里和單向鏈表基本一致,因為遍歷的時候只用到了一個指針。
//打印鏈表 void TraverseDbLinkList(pNODE pHead) { pNODE pt = pHead->pNext; printf("打印鏈表如:"); while (pt != NULL) { printf("%d ", pt->data); pt = pt->pNext; } putchar('\n'); } //判斷鏈表是否為空 int IsEmptyDbLinkList(pNODE pHead) { pNODE pt = pHead->pNext; if (p == NULL) return 1; else return 0; } //計算鏈表的長度 int GetLengthDbLinkList(pNODE pHead) { int length = 0; pNODE pt = pHead->pNext; while (pt != NULL) { length++; pt = pt->pNext; } return length; }
(3)這部分是向雙向鏈表插入節點,也跟單向鏈表很多相似的地方。
每次我們添加一個節點都有很多地方要調節的,也就是每個節點的那兩個指針,一定要認真仔細自己動手寫一遍,有可能有些細節就會出錯。這里有一個地方需要注意,是和單向鏈表不同的地方,單向鏈表在插入節點的時候不需要判斷最后一個節點是否為空,因為這不影響程序的結果,但是對於雙向鏈表就不一樣了,因為我們后面要用到最后一個節點的一個指針指向前一個節點,如果最后一個節點是空的話(就是程序中的pt),就不存在pt->pPre了,那么程序運行到這里時就會報錯,所以我們要加個判斷,判斷此時節點是NULL的話就不需要控制它的指針了。
//向雙向鏈表中插入節點 int InsertEleDbLinkList(pNODE pHead, int pos, int data) { pNODE pt = NULL, p_new = NULL; if (pos > 0 && pos < GetLengthDbLinkList(pHead)+2) { p_new = (pNODE)malloc(sizeof(NODE)); if (NULL == p_new) { printf("內存分配失敗!\n"); exit(EXIT_FAILURE); } while (1) { pos--; if (0 == pos) break; pHead = pHead->pNext; } pt = pHead->pNext; p_new->data = data; p_new->pNext = pt; if (NULL != pt) pt->pPre = p_add; p_new->pPre = pHead; pHead->pNext = p_new; return 1; } else return 0; }
(4)這部分是從鏈表中刪除節點,當然這里和單向鏈表差不多,要注意的地方和插入節點時是一樣的,上面已經說明了。
//從鏈表中刪除節點 int DeleteEleDbLinkList(pNODE pHead, int pos) { pNODE pt = NULL; if (pos > 0 && pos < GetLengthDbLinkList(pHead) + 1) { while (1) { pos--; if (0 == pos) break; pHead = pHead->pNext; } pt = pHead->pNext->pNext; free(pHead->pNext); pHead->pNext = pt; if (NULL != pt) pt->pPre = pHead; return 1; } else return 0; }
(5)這部分是用來釋放內存的,注意的地方和上面一樣。
//刪除整個鏈表,釋放內存 void FreeMemory(pNODE *ppHead) { pNODE pt = NULL; while (*ppHead != NULL) { pt = (*ppHead)->pNext; free(*ppHead); if (NULL != pt) pt->pPre = NULL; *ppHead = pt; } }
main.cpp 測試程序源文件——通過簡單的交互信息來測試各個函數功能是否正確。
#include <stdio.h> #include <stdlib.h> #include "DbLinkList.h" int main(void) { int flag = 0, length = 0; int position = 0, value = 0; pNODE head = NULL; head = CreateDbLinkList(); flag = IsEmptyDbLinkList(head); if (flag) printf("雙向鏈表為空!\n"); else { length = GetLengthDbLinkList(head); printf("雙向鏈表的長度為:%d\n", length); TraverseDbLinkList(head); } printf("請輸入要插入節點的位置和元素值(兩個數用空格隔開):"); scanf("%d %d", &position, &value); flag = InsertEleDbLinkList(head, position, value); if (flag) { printf("插入節點成功!\n"); TraverseDbLinkList(head); } else printf("插入節點失敗!\n"); flag = IsEmptyDbLinkList(head); if (flag) printf("雙向鏈表為空,不能進行刪除操作!\n"); else { printf("請輸入要刪除節點的位置:"); scanf("%d", &position); flag = DeleteEleDbLinkList(head, position); if (flag) { printf("刪除節點成功!\n"); TraverseDbLinkList(head); } else printf("刪除節點失敗!\n"); } FreeMemory(&head); if (NULL == head) printf("已成功刪除雙向鏈表,釋放內存完成!\n"); else printf("刪除雙向鏈表失敗,釋放內存未完成!\n"); return 0; }