我们以及学习了无头单链表,可以发现它有点麻烦
1.单链表不能从后面往前
2.找不到它的前驱(上一个地址)
(尾插,尾删,中插,中删)都要找到它的前一个节点
3.没有带头的节点:要用二级指针进行传参,不用改变传过来指针
那么我们可以介绍一下带头双向循环链表的好处
1.带头节点的好处
:不存储有效数据,带哨兵位的头节点不存入链表的长度,使得尾插更加方便,每次都在头后进行连接
2.双向的好处
:方便找到他的前一个节点
3.循环的好处
:头指向尾,尾指向头,头的前一个节点就是尾,方便找尾节点
list.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| #define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include<stdio.h> #include<stdlib.h> #include<assert.h> typedef int listdata; typedef struct listnode { struct listnode*prev; struct listnode*next; listdata data; }listnode;
listnode* listinit();
void listpushback(listnode*phead, listdata x);
void listprint(listnode*phead);
void listpushfront(listnode* phead, listdata x);
void listpopfront(listnode*phead);
void listpopback(listnode*phead);
listnode* listfind(listnode*phead,listdata x);
void listinsert(listnode*phead, listdata x);
void listerase(listnode*pos);
void listdestroy(listnode*phead);
|
list.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
| #define _CRT_SECURE_NO_WARNINGS 1 #include"list.h"
listnode* buynode(listdata x) { listnode*newnode = (listnode*)malloc(sizeof(listnode)); newnode->next = NULL; newnode ->prev = NULL; newnode->data = x; return newnode; }
listnode* listinit() { listnode*phead = buynode(0); 头的前面和后面都是指向自己 phead->next = phead; phead->prev = phead; return phead; }
void listpushback(listnode*phead, listdata x) { listnode*tail = phead->prev; listnode*newnode = buynode(x); tail->next = newnode; newnode->prev = tail; newnode->next = phead; phead->prev = newnode;
}
void listprint(listnode*phead) {
assert(phead); listnode*cur = phead->next; while (cur != phead) { printf("%d->", cur->data); cur = cur->next; } printf("NULL"); printf("\n");
}
void listpushfront(listnode* phead, listdata x) { listnode*newnode = buynode(x); listnode*first = phead->next; phead->next = newnode; newnode->prev = phead; newnode->next = first; first->prev = newnode;
}
void listpopfront(listnode*phead) { listnode*first = phead->next; listnode*second = first->next; phead->next = second; second->prev = phead; free(first); first = NULL;
}
void listpopback(listnode*phead) { listnode*tail = phead->prev; listnode*prev = tail->prev; phead->prev = prev; prev->next = phead; free(tail); tail = NULL;
}
listnode* listfind(listnode*phead,listdata x) { assert(phead); listnode*cur = phead->next; while (cur != phead) { if (cur->data == x) { return cur; } cur = cur->next; } return NULL; }
void listinsert(listnode*pos, listdata x) { assert(pos); listnode*newnode = buynode(x); listnode*prev = pos->prev; prev->next = newnode; newnode->prev = prev; newnode->next = pos; pos -> prev = newnode; }
void listerase(listnode*pos) { assert(pos); listnode*next = pos->next; listnode*prev = pos->prev; prev->next = next; next->prev = prev; free(pos); pos = NULL; }
void listdestroy(listnode*phead) { assert(phead); listnode*cur = phead->next; while (cur != phead) { listnode*next = cur->next; free(cur); cur =next; } phead = NULL; }
|
test.c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
|
//带头双向循环链表,最有用的链表结构,任意位置插入删除都是O(1), //查找还是O(N);但是查找的时候有更有的算法 //1.平衡搜索树(AVL树和红黑树) //2.哈希表 //3.B树 B +树系列 //跳表,布隆过滤器,位图
//但是我们其实只需要用insert 和erase就可以完成各种操作 void testlist() { //我们要创建一个带头双向循环链表 //即尾指向头,头指向尾,一个节点可以找到前后两个节点 //首先就要初始化一个哨兵位的头节点 listnode*plist = listinit(); listpushback(plist, 1); listpushback(plist, 2); listpushback(plist, 3); listpushback(plist, 4); listpushback(plist, 5); listpopfront(plist); listprint(plist); listpopback(plist); listpushfront(plist,0); listnode* pos=listfind(plist,3); if (pos) { //查找附带着修改的作用,找的同时可以对他进行修改 pos->data = 30; printf("find\n"); listprint(plist); } //想在3的前面插入一个300 listinsert(pos, 300); //把pos的位置给删掉 listerase(pos); listinsert(pos, 40); listprint(plist); listdestroy(plist); }
int main() { testlist(); return 0; }
|
我以及将代码上传到我的gitee上面去了
wcode: 代码收集 - Gitee.com