雙向循環鏈表和它名字的表意一樣,就是把雙向鏈表的兩頭連接,使其成為了一個環狀鏈表。只需要將表中最后一個節點的next指針指向頭節點,頭節點的prior指針指向尾節點,鏈表就能成環兒,如圖所示:
需要注意的是,雖然雙向循環鏈表成環狀,但本質上還是雙向鏈表,因此在雙向循環鏈表中,依然能夠找到頭指針和頭節點等。雙向循環鏈表和雙向鏈表相比,唯一的不同就是雙向循環鏈表首尾相連,其他都完全一樣。
注意:因為我上面已經講了雙向鏈表,所以這里只注重講他們的實現差異。另因為帶頭節點會更好操作,所以我的代碼都有頭節點。
1、雙向循環鏈表的創建
初始化時需要將頭節點的next和prior都指向自己。
//1、初始化雙向循環鏈表(帶頭節點)
Status initLinkList(LinkList *list){
//創建頭節點
*list = malloc(sizeof(Node));
if (*list == NULL) {
return ERROR;
}
//前驅和后繼都指向自己
(*list)->prior = *list;
(*list)->data = -1;
(*list)->next = *list;
printf("已初始化鏈表~ ");
return OK;
}
2、遍歷雙向循環鏈表
注意它的尾節點的next不再是Null,而是頭節點
//2、遍歷雙向循環鏈表
void printfLinkLisk(LinkList list){
printf("遍歷鏈表: ");
if (list == NULL || list->next == list) {
printf("這是一個空鏈表 ");
return;
}
LinkList p = list;
//判斷next是否全部正確
printf("根據next從前往后遍歷:");
while (p->next != list) {
printf("%d ",p->next->data);
p = p->next;
}
printf(" ");
//判斷prior是否全部正確
printf("根據prior從后往前遍歷:");
while (p != list) {
printf("%d ",p->data);
p = p->prior;
}
printf(" ");
}
3、根據索引位置添加節點
這里不需要判斷尾節點的next是否為Null,因為它會指向頭節點。
//3、根據索引位置插入數據至鏈表中
Status insertLinkList(LinkList *list, int index, ElemType data){
if (list == NULL || index < 0) {
return ERROR;
}
int i = 0;
LinkList priorNode = *list;
//判斷插入的位置,這里開始位置是0,index超過鏈表長度則插入末尾
while (i < index && priorNode->next != *list) {
priorNode = priorNode->next;
i++;
}
LinkList newNode = malloc(sizeof(Node));
if (newNode == NULL) {
return ERROR;
}
newNode->data = data;
//插入操作共四步,看好了,別眨眼
//1.將priorNode->next節點的前驅指向新節點
priorNode->next->prior = newNode;
//2.將新節點->next指向原來的priorNode->next
newNode->next = priorNode->next;
//3.將priorNode->next指向新節點
priorNode->next = newNode;
//4.新節點的前驅指向priorNode
newNode->prior = priorNode;
return OK;
}
4、根據索引位置刪除節點
這里不需要判斷尾節點的next是否為Null,因為它會指向頭節點。
//4、根據索引位置刪除節點
Status deleteLinkListByIndex(LinkList *list, int index, ElemType *data){
if (*list == NULL || index < 0) {
return ERROR;
}
LinkList locaNode = *list;
int i = 0;
//注意別刪了頭節點
while (i <= index) {
locaNode = locaNode->next;
if (locaNode == *list) {
printf("沒有這個你想要刪除的節點 ");
return ERROR;
}
i++;
}
//開始刪除,只需要做兩步
locaNode->prior->next = locaNode->next;
locaNode->next->prior = locaNode->prior;
*data = locaNode->data;
free(locaNode);
return OK;
}
5、根據存儲的值刪除節點
這里不需要判斷尾節點的next是否為Null,因為它會指向頭節點。
//5、根據存儲的值刪除節點
Status deleteLinkListByData(LinkList *list, ElemType data){
if (*list == NULL) {
return ERROR;
}
LinkList locaNode = (*list)->next;
while (locaNode != *list) {
if (locaNode->data == data) {
break;
}
locaNode = locaNode->next;
}
if (locaNode == *list) {
printf("沒有這個你想要刪除的節點 ");
return ERROR;
}
//開始刪除,只需要做兩步
locaNode->prior->next = locaNode->next;
locaNode->next->prior = locaNode->prior;
free(locaNode);
return OK;
}
6、根據值查找節點
尾節點的next可是頭節點哦,找到它就是最后一個了。
//6、查找元素
Status selectNode(LinkList list, ElemType data, LinkList *locaNode){
if (list == NULL) {
return ERROR;
}
LinkList p = list->next;
while (p != list) {
if (p->data == data) {
*locaNode = p;
break;
}
p = p->next;
}
if (*locaNode == NULL) {
printf("沒有這個你想要的節點 ");
return ERROR;
}
else {
return OK;
}
}
其它代碼
#include "stdlib.h"
#define OK 1
#define ERROR 0
//元素類型
typedef int ElemType;
//狀態類型
typedef int Status;
//定義節點結構體
typedef struct Node {
struct Node *prior;
ElemType data;
struct Node *next;
} Node;
typedef Node *LinkList;
int main(int argc, const char * argv[]) {
LinkList list;
initLinkList(&list);
for (int i = 0; i < 10; i ++) {
insertLinkList(&list, i, i);
}
printfLinkLisk(list);
int index, data;
printf("輸入你想插入的位置(從0開始)和存儲的值:");
scanf("%d %d",&index,&data);
insertLinkList(&list, index, data);
printfLinkLisk(list);
printf("輸入你想刪除的位置(從0開始):");
scanf("%d",&index);
deleteLinkListByIndex(&list, index, &data);
printfLinkLisk(list);
printf("輸入你想刪除的節點的值(只刪最前的那個):");
scanf("%d",&data);
deleteLinkListByData(&list, data);
printfLinkLisk(list);
printf(" ");
return 0;
}
輸出結果:
—END—
審核編輯 :李倩
-
節點
+關注
關注
0文章
218瀏覽量
24431 -
鏈表
+關注
關注
0文章
80瀏覽量
10560
原文標題:【C語言教程】“雙向循環鏈表”學習總結及其代碼實現!
文章出處:【微信號:cyuyanxuexi,微信公眾號:C語言編程學習基地】歡迎添加關注!文章轉載請注明出處。
發布評論請先 登錄
相關推薦
評論