了解链表
由于之前已经有一篇文章介绍链表,本次直接上八种链表的代码
具体前一篇文章阅读此处:链表介绍
八种链表代码
单向链表
节点当中存放数据以及指向下一个节点的指针
代码:
#define _CRT_SECURE_NO_WARINGS 1#include <stdio.h> #include <stdlib.h> #include <string.h> #include <assert.h>typedef int DataType;//创建单链表结构 typedef struct SListNode {DataType data;struct SListNode* next; }SLTNode;//打印 void SLTPrint(SLTNode* phead) {//断言指针//assert(phead);SLTNode* cur = phead;while (cur){printf("%d->", cur->data);cur = cur->next;}printf("NULL\n"); }//开辟空间 SLTNode* SLTSpace(DataType x) {//开辟空间SLTNode* p = (SLTNode*)malloc(sizeof(SLTNode));if (p == NULL){perror("Space malloc fail");return NULL;}p->data = x;p->next = NULL;return p; }//头插 void SLPushFront(SLTNode** pphead, DataType x) {//断言指针assert(pphead);//创建节点SLTNode* newNode = SLTSpace(x);//无节点的情况下直接插入if (*pphead == NULL){*pphead = newNode;return;}//节点存在的情况下插入newNode->next = *pphead;*pphead = newNode;}//头删 void SLPopFront(SLTNode** pphead) {//断言指针assert(pphead);assert(*pphead);//只有一个节点的情况下if ((*pphead)->next == NULL){//直接进行删除释放(*pphead)->data = 0;free(*pphead);*pphead = NULL;return;}//有多个节点的情况下SLTNode* cur = *pphead;SLTNode* tail = *pphead;//tail表示头节点的下一个节点tail = cur->next;//释放头节点cur->data = 0;free(cur);*pphead = tail;//将tail置NULL 避免野指针tail = NULL; }//尾插 void SLPushBank(SLTNode** pphead, DataType x) {//断言指针assert(pphead);//assert(*pphead);无节点的情况不能断言//开辟新节点SLTNode* newNode = SLTSpace(x);//没有节点的情况if (*pphead == NULL){//直接插入*pphead = newNode;return;}//存在节点的时候//循环遍历找尾//找尾进行尾插SLTNode* cur = *pphead;while (cur->next){cur = cur->next;}//尾插链接cur->next = newNode; }//尾删 void SLPopBank(SLTNode** pphead) {//断言指针assert(pphead);assert(*pphead);//只有一个节点的情况if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;return;}//进行找尾SLTNode* cur = *pphead;SLTNode* tail = *pphead;while (tail->next){//cur表示最后一个节点的前一个节点cur = tail;tail = tail->next;}free(tail);tail = NULL;cur->next = NULL; }//查找 SLTNode* SLFind(SLTNode* phead, DataType x) {//断言指针assert(phead);//循环遍历查找SLTNode* cur = phead;while (cur){if (cur->data == x){return cur;}cur = cur->next;}//找不见的时候返回NULLreturn NULL; }//销毁 void SLDestroy(SLTNode** pphead) {//断言指针assert(*pphead);//循环遍历销毁节点SLTNode* cur = *pphead;SLTNode* tail = *pphead;while (cur){tail = cur;cur = cur->next;tail->data = 0;free(tail);}*pphead = NULL; }//在pos位置前插入 void SLInsert(SLTNode** pphead, SLTNode* pos, DataType x) {//断言指针assert(pphead);//申请节点SLTNode* newnode = SLTSpace(x);//pos为NULLif (pos == NULL){// *pphead也为NULL,直接插入if ((*pphead) == NULL){*pphead = newnode;newnode->next = pos;return;}//pos为NULL 且*pphead不为空的情况//说明最后一个节点的下一个节点就是尾插SLPushBank(pphead, x);return;}//pos是头节点的情况,直接进行头插if (pos == (*pphead)){//头插SLPushFront(pphead, x);return;}//pos不为空且不是头节点的情况SLTNode* cur = *pphead;SLTNode* prev = *pphead;while (cur){if (cur == pos){prev->next = newnode;newnode->next = pos;return;}prev = cur;cur = cur->next;}perror("pos Does not exist"); }//在pos位置前删除 void SLErase(SLTNode** pphead, SLTNode* pos) {//pos为空其实就是尾删(以上函数已经实现)//pos和为头节点无法删除,头节点前无任何节点//pos为头节点且都为NULL ,无节点无法删除//即pos不为头节点,且pos不能为空//断言指针assert(pphead);assert(*pphead);//头节点不能为空,无法删除assert(pos);//若pos为第二个节点,删除pos的前一个节点就是头删if ((*pphead)->next == pos){//头删SLPopFront(pphead);return;}//pos为头节点无法删除,头节点前无任何节点if (pos == (*pphead)){perror("pos == phead");return;}//不是头删以及不是头的情况SLTNode* cur = *pphead;SLTNode* pevr = *pphead;SLTNode* ppevr = *pphead;while (cur){if (cur == pos){free(pevr);pevr = NULL;ppevr->next = cur;return;}ppevr = pevr;pevr = cur;cur = cur->next;}perror("pos Does not exist"); }//在pos位置后插入 void SLInsertAfter(SLTNode* pos, DataType x) {//pos为空的情况下,无法插入assert(pos);//创建节点SLTNode* newnode = SLTSpace(x);SLTNode* plast = pos->next;pos->next = newnode;newnode->next = plast; }//在pos位置后删除 void SLEraseAfter(SLTNode* pos) {//pos不能为NULL,为NULL无法删除assert(pos);//pos后一个节点为NULL的情况,无法删除assert(pos->next);SLTNode* cur = pos->next;SLTNode* plast = pos->next->next;free(cur);cur = NULL;pos->next = plast; }int main() {//创建变量SLTNode* sl = NULL;SLPushFront(&sl, 1);//头插SLTPrint(sl);//打印SLPushFront(&sl, 2);//头插SLPushFront(&sl, 3);//头插SLTPrint(sl);//打印SLPopFront(&sl);//头删SLPopFront(&sl);//头删SLTPrint(sl);//打印SLPopFront(&sl);//头删SLTPrint(sl);//打印SLPushBank(&sl, 6);//尾插SLPushBank(&sl, 7);//尾插SLPushBank(&sl, 8);//尾插SLTPrint(sl);//打印SLPopBank(&sl);//尾删SLTPrint(sl);//打印SLTNode* ret = SLFind(sl, 7);//查找printf("%d\n", ret->data);SLInsert(&sl, ret, 8);//在pos位置前插入SLTPrint(sl);//打印SLErase(&sl, ret);//在pos位置前删除SLTPrint(sl);//打印SLInsertAfter(ret, 9);//在pos位置后插入SLTPrint(sl);//打印SLEraseAfter(ret);//在pos位置后删除SLTPrint(sl);//打印SLDestroy(&sl);//销毁SLTPrint(sl);//打印return 0; }
单向带头链表
节点中存放数据以及指向下一个节点的指针,且会单独开一个哨兵位的头节点,该头节点一般不存放有效数据。
代码:
#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h> #include <stdlib.h> #include <assert.h>typedef int DataType;//定义结构 typedef struct HSTNode {DataType data;struct HSTNode* next; }HSTNode;//初始化头节点(创建哨兵位的头节点) void HSTInit(HSTNode** pphead, DataType x) {//开辟空间,带头节点assert(pphead);HSTNode* cur = (HSTNode*)malloc(sizeof(HSTNode));if (cur == NULL){perror("head malloc fail");return;}cur->data = x;cur->next = NULL;*pphead = cur; }//开空间 HSTNode* HSTSpace(DataType x) {HSTNode* newnode = (HSTNode*)malloc(sizeof(HSTNode));if (newnode == NULL){perror("head malloc fail");return;}newnode->data = x;newnode->next = NULL;return newnode; }//打印 void HSTPrint(HSTNode* phead) {//必须存在哨兵位的头节点assert(phead);HSTNode* cur = phead;while (cur){printf("%d->", cur->data);cur = cur->next;}printf("NULL\n"); }//头插(插到哨兵位头节点的后面) void HSTPushFront(HSTNode** pphead, DataType x) {//必须存在头节点,断言头节点assert(pphead);assert(*pphead);//开辟空间HSTNode* newnode = HSTSpace(x);//直接插入HSTNode* cur = (*pphead)->next;(*pphead)->next = newnode;newnode->next = cur; }//头删 void HSTPopFront(HSTNode** pphead) {//带哨兵位的头节点必须存在assert(pphead);assert(*pphead);//只有哨兵位头节点一个节点的情况不能删除if ((*pphead)->next == NULL){perror("is NULL");return;}HSTNode* cur = (*pphead)->next->next;HSTNode* pevr = (*pphead)->next;free(pevr);pevr = NULL;(*pphead)->next = cur; }//尾插 void HSTPushBank(HSTNode** pphead, DataType x) {//哨兵位的头节点不能为空assert(pphead);assert(*pphead);//开辟节点空间HSTNode* newnode = HSTSpace(x);HSTNode* cur = *pphead;HSTNode* pevr = *pphead;while (cur){pevr = cur;cur = cur->next;}pevr->next = newnode; }//尾删 void HSTPopBank(HSTNode** pphead) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//没有数据的时候无法删除(仅有哨兵位的头节点)if ((*pphead)->next == NULL){perror("is NULL");return;}//存在数据找尾释放HSTNode* cur = *pphead;HSTNode* pevr = *pphead;while (cur->next){pevr = cur;cur = cur->next;}free(cur);cur = NULL;pevr->next = NULL; }//查找 HSTNode* HSTFind(HSTNode* phead, DataType x) {//保证哨兵位的头节点存在assert(phead);//遍历查找HSTNode* cur = phead;while (cur){if (cur->data == x){return cur;}cur = cur->next;}return NULL; }//在pos位置前插入 void SHTInsert(HSTNode** pphead, HSTNode* pos, DataType x) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//pos不能为哨兵位的头节点if ((*pphead) == pos){perror("(*pphead) == pos");return;}//pos为空,表示pos为最后一个节点的下一个节点//在pos前插入实际上是尾插if (pos == NULL){//尾插HSTPushBank(pphead, x);return;}//获取节点HSTNode* newnode = HSTSpace(x);//进行插入HSTNode* cur = *pphead;HSTNode* pevr = *pphead;while (cur){if (cur == pos){pevr->next = newnode;newnode->next = pos;return;}pevr = cur;cur = cur->next;}perror("pos Does not exist"); }//在pos位置前删除 void SHTErase(HSTNode** pphead, HSTNode* pos) {//保证哨兵位的头节点必须存在assert(*pphead);assert(pphead);//若只有头或pos为哨兵位头节点的下一个节点情况下不能删除if ((*pphead)->next == pos){perror("*pphead->next==pos");return;}//pos为哨兵位的头节点的情况下不能删除if ((*pphead) == pos){perror("(*pphead) == pos");return;}//pos既不为哨兵位头节点,也不是头节点的下一个节点//若pos为空,则是尾删//以及pos不为空的情况HSTNode* cur = *pphead;HSTNode* pevr = *pphead;while (cur){if (cur->next == pos){free(cur);pevr->next = pos;cur = NULL;return;}pevr = cur;cur = cur->next;}perror("pos Does not exist"); }//在pos位置后插入 void SHTInsertAfert(HSTNode* pos, DataType x) {//pos为空不能插入//保证头节点存在assert(pos);//获取节点HSTNode* newnode = HSTSpace(x);//直接插入HSTNode* cur = pos->next;pos->next = newnode;newnode->next = cur; }//在pos位置后删除 void SHTEraseAfert(HSTNode* pos) {//pos为空不能删除assert(pos);//pos的下一个元素为NULL,不能删除if (pos->next == NULL){perror("pos->next == NULL");return;}//进行删除HSTNode* perv = pos->next;HSTNode* cur = pos->next->next;free(perv);perv = NULL;pos->next = cur;}//销毁 void HSTDestroy(HSTNode** pphead) {//哨兵位的头节点也进行销毁//手心断定哨兵位的头节点时存在的assert(pphead);assert(*pphead);//循环遍历销毁HSTNode* cur = *pphead;HSTNode* next = *pphead;while (cur){next = cur->next;free(cur);cur = next;}//销毁后将哨兵位的头节点置空,避免野指针*pphead = NULL; }int main() {HSTNode* sl = NULL;//初始化头节点(创建哨兵位的头节点)HSTInit(&sl, 0);HSTPrint(sl);//打印//头插HSTPushFront(&sl, 1);HSTPushFront(&sl, 2);HSTPushFront(&sl, 3);HSTPushFront(&sl, 4);HSTPrint(sl);//打印//头删HSTPopFront(&sl);HSTPopFront(&sl);HSTPopFront(&sl);HSTPopFront(&sl);HSTPrint(sl);//打印//尾插HSTPushBank(&sl, 7);HSTPushBank(&sl, 8);HSTPushBank(&sl, 9);HSTPrint(sl);//打印//尾删HSTPopBank(&sl);HSTPopBank(&sl);HSTPrint(sl);//打印//查找HSTNode* ret = HSTFind(sl, 7);printf("%d\n", ret->data);//在pos位置前插入SHTInsert(&sl, ret, 1);SHTInsert(&sl, NULL, 3);HSTPrint(sl);//打印//在pos位置前删除SHTErase(&sl, ret);SHTErase(&sl, NULL);HSTPrint(sl);//打印//在pos位置后插入SHTInsertAfert(ret, 6);SHTInsertAfert(sl, 9);HSTPrint(sl);//打印//在pos位置后删除SHTEraseAfert(ret);SHTEraseAfert(sl);HSTPrint(sl);//打印//销毁HSTDestroy(&sl);//销毁之后无法打印//HSTPrint(sl);//打印return 0; }
单向循环链表
节点中存放数据以及指向下一个节点的指针,且尾节点中存放的指向下一个节点的指针为头节点的地址,形成尾首相连为一个循环。
代码:
#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h> #include <stdlib.h> #include <assert.h>typedef int DataType;//定义结构 typedef struct HSTNode {DataType data;struct HSTNode* next; }HSTNode;//初始化头节点(创建哨兵位的头节点) void HSTInit(HSTNode** pphead, DataType x) {//开辟空间,带头节点assert(pphead);HSTNode* cur = (HSTNode*)malloc(sizeof(HSTNode));if (cur == NULL){perror("head malloc fail");return;}cur->data = x;cur->next = NULL;*pphead = cur; }//开空间 HSTNode* HSTSpace(DataType x) {HSTNode* newnode = (HSTNode*)malloc(sizeof(HSTNode));if (newnode == NULL){perror("head malloc fail");return;}newnode->data = x;newnode->next = NULL;return newnode; }//打印 void HSTPrint(HSTNode* phead) {//必须存在哨兵位的头节点assert(phead);HSTNode* cur = phead;while (cur){printf("%d->", cur->data);cur = cur->next;}printf("NULL\n"); }//头插(插到哨兵位头节点的后面) void HSTPushFront(HSTNode** pphead, DataType x) {//必须存在头节点,断言头节点assert(pphead);assert(*pphead);//开辟空间HSTNode* newnode = HSTSpace(x);//直接插入HSTNode* cur = (*pphead)->next;(*pphead)->next = newnode;newnode->next = cur; }//头删 void HSTPopFront(HSTNode** pphead) {//带哨兵位的头节点必须存在assert(pphead);assert(*pphead);//只有哨兵位头节点一个节点的情况不能删除if ((*pphead)->next == NULL){perror("is NULL");return;}HSTNode* cur = (*pphead)->next->next;HSTNode* pevr = (*pphead)->next;free(pevr);pevr = NULL;(*pphead)->next = cur; }//尾插 void HSTPushBank(HSTNode** pphead, DataType x) {//哨兵位的头节点不能为空assert(pphead);assert(*pphead);//开辟节点空间HSTNode* newnode = HSTSpace(x);HSTNode* cur = *pphead;HSTNode* pevr = *pphead;while (cur){pevr = cur;cur = cur->next;}pevr->next = newnode; }//尾删 void HSTPopBank(HSTNode** pphead) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//没有数据的时候无法删除(仅有哨兵位的头节点)if ((*pphead)->next == NULL){perror("is NULL");return;}//存在数据找尾释放HSTNode* cur = *pphead;HSTNode* pevr = *pphead;while (cur->next){pevr = cur;cur = cur->next;}free(cur);cur = NULL;pevr->next = NULL; }//查找 HSTNode* HSTFind(HSTNode* phead, DataType x) {//保证哨兵位的头节点存在assert(phead);//遍历查找HSTNode* cur = phead;while (cur){if (cur->data == x){return cur;}cur = cur->next;}return NULL; }//在pos位置前插入 void SHTInsert(HSTNode** pphead, HSTNode* pos, DataType x) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//pos不能为哨兵位的头节点if ((*pphead) == pos){perror("(*pphead) == pos");return;}//pos为空,表示pos为最后一个节点的下一个节点//在pos前插入实际上是尾插if (pos == NULL){//尾插HSTPushBank(pphead, x);return;}//获取节点HSTNode* newnode = HSTSpace(x);//进行插入HSTNode* cur = *pphead;HSTNode* pevr = *pphead;while (cur){if (cur == pos){pevr->next = newnode;newnode->next = pos;return;}pevr = cur;cur = cur->next;}perror("pos Does not exist"); }//在pos位置前删除 void SHTErase(HSTNode** pphead, HSTNode* pos) {//保证哨兵位的头节点必须存在assert(*pphead);assert(pphead);//若只有头或pos为哨兵位头节点的下一个节点情况下不能删除if ((*pphead)->next == pos){perror("*pphead->next==pos");return;}//pos为哨兵位的头节点的情况下不能删除if ((*pphead) == pos){perror("(*pphead) == pos");return;}//pos既不为哨兵位头节点,也不是头节点的下一个节点//若pos为空,则是尾删//以及pos不为空的情况HSTNode* cur = *pphead;HSTNode* pevr = *pphead;while (cur){if (cur->next == pos){free(cur);pevr->next = pos;cur = NULL;return;}pevr = cur;cur = cur->next;}perror("pos Does not exist"); }//在pos位置后插入 void SHTInsertAfert(HSTNode* pos, DataType x) {//pos为空不能插入//保证头节点存在assert(pos);//获取节点HSTNode* newnode = HSTSpace(x);//直接插入HSTNode* cur = pos->next;pos->next = newnode;newnode->next = cur; }//在pos位置后删除 void SHTEraseAfert(HSTNode* pos) {//pos为空不能删除assert(pos);//pos的下一个元素为NULL,不能删除if (pos->next == NULL){perror("pos->next == NULL");return;}//进行删除HSTNode* perv = pos->next;HSTNode* cur = pos->next->next;free(perv);perv = NULL;pos->next = cur;}//销毁 void HSTDestroy(HSTNode** pphead) {//哨兵位的头节点也进行销毁//手心断定哨兵位的头节点时存在的assert(pphead);assert(*pphead);//循环遍历销毁HSTNode* cur = *pphead;HSTNode* next = *pphead;while (cur){next = cur->next;free(cur);cur = next;}//销毁后将哨兵位的头节点置空,避免野指针*pphead = NULL; }int main() {HSTNode* sl = NULL;//初始化头节点(创建哨兵位的头节点)HSTInit(&sl, 0);HSTPrint(sl);//打印//头插HSTPushFront(&sl, 1);HSTPushFront(&sl, 2);HSTPushFront(&sl, 3);HSTPushFront(&sl, 4);HSTPrint(sl);//打印//头删HSTPopFront(&sl);HSTPopFront(&sl);HSTPopFront(&sl);HSTPopFront(&sl);HSTPrint(sl);//打印//尾插HSTPushBank(&sl, 7);HSTPushBank(&sl, 8);HSTPushBank(&sl, 9);HSTPrint(sl);//打印//尾删HSTPopBank(&sl);HSTPopBank(&sl);HSTPrint(sl);//打印//查找HSTNode* ret = HSTFind(sl, 7);printf("%d\n", ret->data);//在pos位置前插入SHTInsert(&sl, ret, 1);SHTInsert(&sl, NULL, 3);HSTPrint(sl);//打印//在pos位置前删除SHTErase(&sl, ret);SHTErase(&sl, NULL);HSTPrint(sl);//打印//在pos位置后插入SHTInsertAfert(ret, 6);SHTInsertAfert(sl, 9);HSTPrint(sl);//打印//在pos位置后删除SHTEraseAfert(ret);SHTEraseAfert(sl);HSTPrint(sl);//打印//销毁HSTDestroy(&sl);//销毁之后无法打印//HSTPrint(sl);//打印return 0; }
单向带头循环链表
节点中存放数据以及指向下一个节点的指针,会开辟一个节点空间用来做哨兵位的头节点,一般头节点中不存放有效数据,且尾节点中存放的指向下一个节点的指针为哨兵位头节点的地址,形成尾首相连为一个循环。
代码:
#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h> #include <stdlib.h> #include <assert.h>//创建节点 typedef int DataType;typedef struct HPLSTNode {DataType data;struct HPLST* next; }HPLSTNode;//初始化哨兵位的头节点 void HPLSTInit(HPLSTNode** pphead, DataType x) {//断言指针assert(pphead);//申请节点HPLSTNode* cur = (HPLSTNode*)malloc(sizeof(HPLSTNode));if (cur == NULL){perror("mallc fail");return;}//开辟成功cur->next = cur;cur->data = x;*pphead = cur; }//创建节点 HPLSTNode* HPLSTSpace(DataType x) {//开辟空间HPLSTNode* newnode = (HPLSTNode*)malloc(sizeof(HPLSTNode));if (newnode == NULL){perror("malloc fail");return NULL;}newnode->next = NULL;newnode->data = x;return newnode; }//打印 void HPLSTPrint(HPLSTNode* phead) {if (phead == NULL){printf("NULL\n");return;}//哨兵位的头节点一定存在printf("%d->", phead->data);HPLSTNode* cur = phead->next;while (cur != phead){printf("%d->", cur->data);cur = cur->next;}printf("head\n"); }//头插 void HPLSTPushFront(HPLSTNode** pphead, DataType x) {//带哨兵位的头节点必须存在assert(pphead);assert(*pphead);//创建节点HPLSTNode* newnode = HPLSTSpace(x);//直接插入HPLSTNode* next = (*pphead)->next;(*pphead)->next = newnode;newnode->next = next; }//头删 void HPLSTPopFront(HPLSTNode** pphead) {//带哨兵位的头节点必须存在assert(pphead);assert(*pphead);//除了哨兵位头节点,不存在其他节点的情况下不可删除if ((*pphead)->next == (*pphead)){assert(NULL);}//具有其他节点的情况可以删除HPLSTNode* cur = (*pphead)->next;HPLSTNode* next = cur->next;cur->next = NULL;free(cur);cur = NULL;(*pphead)->next = next; }//尾插 void HPLSTPushBank(HPLSTNode** pphead, DataType x) {//哨兵位的头节点必须存在(即链表不能为NULL)assert(pphead);assert(*pphead);//创建节点HPLSTNode* newnode = HPLSTSpace(x);//找尾进行插入HPLSTNode* cur = *pphead;while (cur->next != (*pphead)){cur = cur->next;}//插入HPLSTNode* next = cur->next;cur->next = newnode;newnode->next = next; }//尾删 void HPLSTPopBank(HPLSTNode** pphead) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//仅有哨兵位的头节点一个节点的时候无法删除if ((*pphead)->next == (*pphead)){assert(NULL);}//有两个或多个节点的情况//找尾删除HPLSTNode* cur = *pphead;HPLSTNode* pevr = *pphead;while (cur->next != (*pphead)){pevr = cur;cur = cur->next;}//删除HPLSTNode* next = cur->next;cur->next = NULL;free(cur);cur = NULL;pevr->next = next; }//查找 HPLSTNode* HPLSTFind(HPLSTNode** pphead, DataType x) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//仅有哨兵位头节点一个节点的时候不可查找//头节点不存有效数据if ((*pphead)->next == (*pphead)){assert(NULL);}//循环遍历查找HPLSTNode* cur = (*pphead)->next;while (cur != (*pphead)){if (cur->data == x){return cur;}cur = cur->next;}return NULL; }//在pos位置前插入 void HPLSTInster(HPLSTNode** pphead, HPLSTNode* pos, DataType x) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//pos为NULL无法插入assert(pos);//获取节点HPLSTNode* newnode = HPLSTSpace(x);//pos为哨兵位的头节点(就是尾插)if (pos == (*pphead)){HPLSTPushBank(pphead, x);return;}//pos不为头节点//找到pos的前一个节点进行插入操作HPLSTNode* cur = *pphead;HPLSTNode* pevr = *pphead;while (cur != pos){pevr = cur;cur = cur->next;}pevr->next = newnode;newnode->next = cur; }//在pos位置前删除 void HPLSTErase(HPLSTNode** pphead, HPLSTNode* pos) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//pos为NULL无法删除assert(pos);//pos为哨兵位的头节点的下一个节点无法删除//因为哨兵位的头节点必须存在if ((*pphead)->next == pos){assert(NULL);return;}//pos为哨兵位的头节点则是尾删if (pos == (*pphead)){//尾删HPLSTPopBank(pphead);return;}//其余情况HPLSTNode* cur = *pphead;HPLSTNode* pevr = *pphead;while (cur->next != pos){pevr = cur;cur = cur->next;}cur->next = NULL;free(cur);cur = NULL;pevr->next = pos; }//在pos位置后插入 void HPLSTInsertAfter(HPLSTNode** pphead, HPLSTNode* pos, DataType x) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//pos为NULL不能插入assert(pos);//判断pos是否为该链表中的节点//…………………… 省略………………//存在的情况//创建节点HPLSTNode* newnode = HPLSTSpace(x);HPLSTNode* next = pos->next;//进行插入pos->next = newnode;newnode->next = next; }//在pos位置后删除 void HPLSTEraseAfter(HPLSTNode** pphead, HPLSTNode* pos) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//pos为NULL不能删除assert(pos);//仅有哨兵位头节点一个节点的情况不能删除if ((*pphead)->next == (*pphead)){assert(NULL);}//pos为尾节点的情况不能删除if (pos->next == (*pphead)){assert(NULL);}HPLSTNode* cur = pos->next;HPLSTNode* next = cur->next;cur->next = NULL;free(cur);cur = NULL;pos->next = next; }//销毁 void HPLSTDestroy(HPLSTNode** pphead) {//无节点的情况下不用销毁assert(pphead);assert(*pphead);//开始销毁HPLSTNode* cur = (*pphead)->next;HPLSTNode* ccur = cur;while (cur != (*pphead)){ccur = cur->next;cur->next = NULL;free(cur);cur = ccur;}cur->next = NULL;free(cur);cur = NULL;ccur = NULL;*pphead = NULL; }int main() {HPLSTNode* sl = NULL;//初始化哨兵位的头节点HPLSTInit(&sl, 0);HPLSTPrint(sl);//打印//头插HPLSTPushFront(&sl, 1);HPLSTPushFront(&sl, 2);HPLSTPushFront(&sl, 3);HPLSTPrint(sl);//打印//头删HPLSTPopFront(&sl);HPLSTPrint(sl);//打印HPLSTPopFront(&sl);HPLSTPrint(sl);//打印HPLSTPopFront(&sl);HPLSTPrint(sl);//打印//尾插HPLSTPushBank(&sl, 4);HPLSTPushBank(&sl, 5);HPLSTPushBank(&sl, 6);HPLSTPrint(sl);//打印//尾删HPLSTPopBank(&sl);HPLSTPrint(sl);//打印HPLSTPopBank(&sl);HPLSTPrint(sl);//打印//查找HPLSTNode* ret = HPLSTFind(&sl, 4);if (ret != NULL) printf("Find: %d\n", ret->data);else printf("Find: NULL\n");//在pos位置前插入HPLSTInster(&sl, ret, 9);HPLSTPrint(sl);//打印HPLSTInster(&sl, sl, 12);HPLSTPrint(sl);//打印HPLSTInster(&sl, sl->next, 16);HPLSTPrint(sl);//打印//查找ret = HPLSTFind(&sl, 4);if (ret != NULL) printf("Find: %d\n", ret->data);else printf("Find: NULL\n");//在pos位置前删除//HPLSTErase(&sl, ret->next);//HPLSTPrint(sl);//打印//HPLSTErase(&sl, NULL);//HPLSTPrint(sl);//打印//HPLSTErase(NULL, ret);//HPLSTPrint(sl);//打印HPLSTErase(&sl, ret);HPLSTPrint(sl);//打印HPLSTErase(&sl, ret);HPLSTPrint(sl);//打印//HPLSTErase(&sl, ret);//HPLSTPrint(sl);//打印//查找ret = HPLSTFind(&sl, 4);if (ret != NULL) printf("Find: %d\n", ret->data);else printf("Find: NULL\n");//在pos位置后插入HPLSTInsertAfter(&sl, ret->next, 45);HPLSTPrint(sl);//打印HPLSTInsertAfter(&sl, ret, 45);HPLSTPrint(sl);//打印//在pos位置后删除HPLSTEraseAfter(&sl, ret);HPLSTPrint(sl);//打印HPLSTEraseAfter(&sl, ret);HPLSTPrint(sl);//打印HPLSTEraseAfter(&sl, ret);HPLSTPrint(sl);//打印HPLSTEraseAfter(&sl, sl);HPLSTPrint(sl);//打印//销毁HPLSTDestroy(&sl);HPLSTPrint(sl);//打印return 0; }
双向链表
节点中存放数据以及两个指针,一个是指向前一个节点的指针,另一个是指向下一个节点的指针。
代码:
#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h> #include <stdlib.h> #include <assert.h>//创建结构 typedef int DataType;typedef struct BSTLNode {DataType data;struct BSTLNode* pevr;struct BSTLNode* next; }BSTLNode;//开辟空间(创建节点) BSTLNode* BSTLSpace(DataType x) {BSTLNode* newnode = (BSTLNode*)malloc(sizeof(BSTLNode));if (newnode == NULL){perror("malloc fail");return;}newnode->data = x;newnode->next = NULL;newnode->pevr = NULL; }//打印 void BSTLPrint(BSTLNode* phead) {BSTLNode* cur = phead;while (cur){printf("%d->", cur->data);cur = cur->next;}printf("NULL\n"); }//头插 void BSTLPushFront(BSTLNode** pphead, DataType x) {//断言指针assert(pphead);//创建节点BSTLNode* newnode = BSTLSpace(x);//无节点的情况if (*pphead == NULL){*pphead = newnode;return;}//存在节点的情况newnode->next = (*pphead);(*pphead)->pevr = newnode;*pphead = newnode; }//头删 void BSTLPopFront(BSTLNode** pphead) {//无节点的情况下不能删除assert(*pphead);assert(pphead);//仅有一个头节点的情况下if ((*pphead)->next == NULL){(*pphead)->next = NULL;(*pphead)->pevr = NULL;free(*pphead);*pphead = NULL;return;}//有节点的情况下删除BSTLNode* cur = (*pphead)->next;free(cur->pevr);cur->pevr = NULL;*pphead = cur; }//尾插 void BSTLPushBank(BSTLNode** pphead, DataType x) {//断言指针assert(pphead);//创建节点BSTLNode* newnode = BSTLSpace(x);//无节点的情况下直接插入if ((*pphead) == NULL){//直接插入*pphead = newnode;return;}//有节点的情况下,找尾插入BSTLNode* cur = *pphead;while (cur->next){cur = cur->next;}cur->next = newnode;newnode->pevr = cur; }//尾删 void BSTLPopBank(BSTLNode** pphead) {//没有节点不能删除assert(pphead);assert(*pphead);//只有一个头节点的情况if ((*pphead)->next == NULL){free(*pphead);*pphead = NULL;return;}//找尾释放删除BSTLNode* cur = *pphead;while (cur->next){cur = cur->next;}BSTLNode* pevr = cur->pevr;cur->pevr = NULL;free(cur);cur = NULL;pevr->next = NULL; }//查找 BSTLNode* BSTLFind(BSTLNode** pphead, DataType x) {//没有节点无法查找assert(*pphead);BSTLNode* cur = *pphead;while (cur){if (cur->data == x){return cur;}}return NULL; }//在pos位置前插入 void BSTLInsert(BSTLNode** pphead, BSTLNode* pos, DataType x) {//断言指针assert(pphead);assert(*pphead);//pos为空实际上是尾插if (pos == NULL){BSTLPushBank(pphead, x);return;}//申请节点BSTLNode* newnode = BSTLSpace(x);//pos为头节点,前面插入便是头插if ((*pphead) == pos){BSTLPushFront(pphead, x);return;}//不为头节点则直接插入BSTLNode* pevr = pos->pevr;pevr->next = newnode;newnode->pevr = pevr;newnode->next = pos; }//在pos位置前删除 void BSTLErase(BSTLNode** pphead, BSTLNode* pos) {//头节点不能为NULLassert(pphead);assert(*pphead);//若为头节点则不能删除if ((*pphead) == pos){perror("pos==phead");return;}//pos为NULL说明是尾删if (pos == NULL){BSTLPopBank(pphead);return;}//pos为第二个节点if ((*pphead)->next == pos){(*pphead)->pevr = NULL;(*pphead)->next = NULL;free(*pphead);pos->pevr = NULL;*pphead = pos;return;}//其余情况BSTLNode* pevr = pos->pevr;BSTLNode* ppevr = pevr->pevr;pevr->pevr = NULL;pevr->next = NULL;free(pevr);pevr = NULL;ppevr->next = pos;pos->pevr = ppevr; }//在pos位置后插入 void BSTLInsertAfter(BSTLNode* pos, DataType x) {//pos不能为空assert(pos);//申请节点BSTLNode* newnode = BSTLSpace(x);//插入BSTLNode* cur = pos->next;pos->next = newnode;newnode->pevr = pos;newnode->next = cur;cur->pevr = newnode; }//在pos位置后删除 void BSTLEraseAfter(BSTLNode* pos) {//pos不能为空,为空则不能删除assert(pos);//pos后一个为NULL 也不能删除assert(pos->next);//删除BSTLNode* cur = pos->next;BSTLNode* next = pos->next->next;cur->next = NULL;cur->pevr = NULL;free(cur);cur = NULL;pos->next = next;//若next不为空则将前一个链接到posif (next != NULL){next->pevr = pos;} }int main() {BSTLNode* sl = NULL;BSTLPushFront(&sl, 1);BSTLPushFront(&sl, 2);BSTLPushFront(&sl, 3);BSTLPrint(sl);//打印BSTLPopFront(&sl);BSTLPopFront(&sl);BSTLPopFront(&sl);BSTLPrint(sl);//打印BSTLPushBank(&sl, 5);BSTLPushBank(&sl, 6);BSTLPushBank(&sl, 7);BSTLPrint(sl);//打印BSTLPopBank(&sl);BSTLPopBank(&sl);BSTLPrint(sl);//打印BSTLNode* ret = BSTLFind(&sl, 5);printf("%d\n", ret->data);BSTLInsert(&sl, ret, 9);BSTLInsert(&sl, NULL, 8);BSTLInsert(&sl, sl, 7);BSTLPrint(sl);//打印BSTLErase(&sl, ret);BSTLPrint(sl);//打印//BSTLErase(&sl, NULL);BSTLErase(&sl, sl);BSTLPrint(sl);//打印BSTLInsertAfter(ret, 89);BSTLPrint(sl);//打印//BSTLInsertAfter(NULL, 89);BSTLInsertAfter(ret->pevr, 89);BSTLPrint(sl);//打印BSTLEraseAfter(ret);BSTLPrint(sl);//打印BSTLEraseAfter(ret->pevr);BSTLPrint(sl);//打印//BSTLEraseAfter(NULL);BSTLPrint(sl);//打印BSTLEraseAfter(sl);BSTLPrint(sl);//打印BSTLEraseAfter(sl);BSTLPrint(sl);//打印//BSTLEraseAfter(sl);BSTLPrint(sl);//打印return 0; }
双向带头链表
节点中存放数据以及两个指针,一个是指向前一个节点的指针,另一个是指向下一个节点的指针,且会单独开辟一个节点空间用来做哨兵位的头节点,一般哨兵位的头节点不存放有效数据。
代码:
#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h> #include <stdlib.h> #include <assert.h>typedef int DataType; //创建结构 typedef struct BHSTLNode {DataType data;struct BHSTLNode* pevr;struct BHSTLNode* next; }BHSTLNode;//初始化(创建带哨兵位的头节点) void BHSTLInit(BHSTLNode** pphead, DataType x) {BHSTLNode* cur = (BHSTLNode*)malloc(sizeof(BHSTLNode));if (cur == NULL){perror("malloc fail");return;}//开辟成功,进行赋值cur->data = x;cur->next = NULL;cur->pevr = NULL;*pphead = cur; }//创建节点(开辟空间) BHSTLNode* BHSTLSpace(DataType x) {BHSTLNode* newnode = (BHSTLNode*)malloc(sizeof(BHSTLNode));if (newnode == NULL){perror("malloc fail");return NULL;}newnode->data = x;newnode->next = NULL;newnode->pevr = NULL;return newnode; }//打印 void BHSTLPrint(BHSTLNode* phead) {BHSTLNode* cur = phead;while (cur){printf("%d->", cur->data);cur = cur->next;}printf("NULL\n"); }//头插 void BHSTLPushFront(BHSTLNode** pphead, DataType x) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//创建节点BHSTLNode* newnode = BHSTLSpace(x);//进行插入BHSTLNode* cur = (*pphead)->next;(*pphead)->next = newnode;newnode->pevr = (*pphead);newnode->next = cur;if (cur != NULL){cur->pevr = newnode;} }//头删 void BHSTLPopFront(BHSTLNode** pphead) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//头节点的下一个节点为NULL不可删除assert((*pphead)->next);//进行删除BHSTLNode* head = (*pphead)->next;BHSTLNode* cur = head->next;head->next = NULL;head->pevr = NULL;free(head);head = NULL;(*pphead)->next = cur;if (cur != NULL){cur->pevr = (*pphead);} }//尾插 void BHSTLPushBank(BHSTLNode** pphead, DataType x) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//创建节点BHSTLNode* newnode = BHSTLSpace(x);//找尾进行插入BHSTLNode* cur = *pphead;while (cur->next){cur = cur->next;}cur->next = newnode;newnode->pevr = cur;newnode->next = NULL; }//尾删 void BHSTLPopBank(BHSTLNode** pphead) {//带哨兵位的头节点不能为空assert(pphead);assert(*pphead);//只有哨兵位的头节点一个节点的时候不能删除assert((*pphead)->next);//找尾删除BHSTLNode* cur = *pphead;while (cur->next){cur = cur->next;}BHSTLNode* pevr = cur->pevr;cur->pevr = NULL;cur->next = NULL;free(cur);cur = NULL;pevr->next = NULL; }//查找 BHSTLNode* BHSTLFind(BHSTLNode** pphead, DataType x) {//带哨兵位的头节点必须存在assert(pphead);assert(*pphead);BHSTLNode* cur = (*pphead)->next;while (cur){if (cur->data == x){return cur;}cur = cur->next;}return NULL; }//在pos位置前插入 void BHSTLInsert(BHSTLNode** pphead, BHSTLNode* pos, DataType x) {//哨兵位的头节点必须存在assert(*pphead);assert(pphead);//pos不能为哨兵位的头节点if (pos == (*pphead)){perror("pos == (*pphead)");return;}//pos为空的情况就是尾插if (pos == NULL){BHSTLPushBank(pphead, x);return;}//获取节点BHSTLNode* newnode = BHSTLSpace(x);//其余情况BHSTLNode* pevr = pos->pevr;pevr->next = newnode;newnode->pevr = pevr;newnode->next = pos;pos->pevr = newnode; }//在pos位置前删除 void BHSTLErase(BHSTLNode** pphead, BHSTLNode* pos) {//哨兵位的头节点assert(pphead);assert(*pphead);//仅有哨兵位头节点一个节点时不可删除assert((*pphead)->next);//pos的前一个节点为头节点则不能删除if (pos->pevr == (*pphead)){perror("pos->pevr == (*pphead)");return;}//pos为哨兵位的头节点则不能删除前面的if (pos == (*pphead)){perror("pos == (*pphead)");exit;}//pos为哨兵位头节点的下一个节点则不能删除前一个节点if (pos == (*pphead)->next){perror("pos == (*pphead)->next");return;}//pos为NULL就是尾删if (pos == NULL){BHSTLPopBank(pphead);return;}//其余情况BHSTLNode* pevr = pos->pevr;BHSTLNode* ppevr = pevr->pevr;pevr->next = NULL;pevr->pevr = NULL;free(pevr);ppevr->next = pos; }//在pos位置后插入 void BHSTLInsertAfter(BHSTLNode* pos, DataType x) {//pos为空不能插入assert(pos);//创建节点BHSTLNode* newnode = BHSTLSpace(x);//直接插入BHSTLNode* cur = pos->next;pos->next = newnode;newnode->next = cur;newnode->pevr = pos;}//在pos位置后删除 void BHSTLEraseAfter(BHSTLNode* pos) {//pos不能为空,为空则不能删除assert(pos);//pos的下一个为NULL,则不能删除assert(pos->next);//进行删除BHSTLNode* cur = pos->next;BHSTLNode* next = pos->next->next;cur->next = NULL;cur->pevr = NULL;free(cur);cur = NULL;pos->next = next;if (next != NULL){next->pevr = pos;} }//销毁 void BHSTLDestroy(BHSTLNode** pphead) {//哨兵位的头节点不能为NULLassert(pphead);assert(*pphead);//循环遍历销毁BHSTLNode* cur = *pphead;BHSTLNode* next = *pphead;while (cur){next = cur - next;cur->next = NULL;cur->pevr = NULL;cur->data = 0;free(cur);cur = next;;}*pphead = NULL; }int main() {BHSTLNode* sl;//头节点BHSTLInit(&sl, 0);BHSTLPrint(sl);//打印//头插BHSTLPushFront(&sl, 1);BHSTLPushFront(&sl, 2);BHSTLPushFront(&sl, 3);BHSTLPrint(sl);//打印//头删BHSTLPopFront(&sl);BHSTLPrint(sl);//打印BHSTLPopFront(&sl);BHSTLPrint(sl);//打印 BHSTLPopFront(&sl);BHSTLPrint(sl);//打印//尾插BHSTLPushBank(&sl, 6);BHSTLPushBank(&sl, 7);BHSTLPushBank(&sl, 8);BHSTLPrint(sl);//打印//尾删BHSTLPopBank(&sl);BHSTLPrint(sl);//打印BHSTLPopBank(&sl);BHSTLPrint(sl);//打印//BHSTLPopBank(&sl);//BHSTLPrint(sl);//打印//BHSTLPopBank(&sl);//BHSTLPrint(sl);//打印//查找BHSTLNode* ret = BHSTLFind(&sl, 6);printf("%d\n", ret->data);//在pos位置前插入BHSTLInsert(&sl, ret, 9);BHSTLPrint(sl);//打印BHSTLInsert(&sl, ret->pevr, 10);BHSTLPrint(sl);//打印//在pos位置前删除BHSTLErase(&sl, ret);BHSTLPrint(sl);//打印//BHSTLErase(&sl, ret->pevr);//BHSTLPrint(sl);//打印return 0; }
双向循环链表
节点中存放数据以及两个指针,一个是指向前一个节点的指针,另一个是指向下一个节点的指针,且尾节点中指向下一个节点的指针存放的是头节点的地址,头节点中的指向前一个节点的指针存放的是尾节点的地址。
代码:
#define _CRT_SECURE_NO_WARNINGS 1#include <stdio.h> #include <stdlib.h> #include <assert.h>typedef int DataType;//创建结构 typedef struct BPLSTNode {DataType data;struct BPLSTNode* pevr;struct BPLSTNode* next; }BPLSTNode;//创建节点 BPLSTNode* BPLSTSpace(DataType x) {//开辟空间BPLSTNode* newnode = (BPLSTNode*)malloc(sizeof(BPLSTNode));//判断是否开辟成功if (newnode == NULL){perror("malloc fail");return NULL;}//开辟成功进行初始化newnode->data = x;newnode->next = NULL;newnode->pevr = NULL;return newnode; }//打印 void BPLSTPrint(BPLSTNode* head) {if (head == NULL){printf("NULL\n");return;}printf("%d->", head->data);BPLSTNode* cur = head->next;//仅有一个节点的情况//两个及多个的情况while (cur != head){printf("%d->", cur->data);cur = cur->next;}printf("head\n"); }//头插 void BPLSTPushFront(BPLSTNode** pphead, DataType x) {//断言指针assert(pphead);//获取节点BPLSTNode* newnode = BPLSTSpace(x);//为空的情况下直接插入if ((*pphead) == NULL){newnode->next = newnode;newnode->pevr = newnode;*pphead = newnode;return;}//存在节点的情况下BPLSTNode* cur = *pphead;BPLSTNode* tail = (*pphead)->pevr;newnode->next = cur;cur->pevr = newnode;newnode->pevr = tail;tail->next = newnode;*pphead = newnode; }//头删 void BPLSTPopFront(BPLSTNode** pphead) {//为空的情况下不能删除assert(pphead);assert(*pphead);//不为空的情况下进行删除//仅有头节点一个节点的情况下。if ((*pphead)->next == (*pphead)){(*pphead)->next = NULL;(*pphead)->pevr = NULL;free(*pphead);*pphead = NULL;return;}//两个及多个节点的情况BPLSTNode* tail = (*pphead)->pevr;BPLSTNode* cur = *pphead;BPLSTNode* next = (*pphead)->next;cur->next = NULL;cur->pevr = NULL;free(cur);tail->next = next;next->pevr = tail;*pphead = next; }//尾插 void BPLSTPushBank(BPLSTNode** pphead, DataType x) {//断言指针assert(pphead);//获取节点BPLSTNode* newnode = BPLSTSpace(x);//无节点的情况下直接插入if ((*pphead) == NULL){newnode->next = newnode;newnode->pevr = newnode;*pphead = newnode;return;}//存在节点的情况//尾部直接插入BPLSTNode* tail = (*pphead)->pevr;BPLSTNode* cur = *pphead;tail->next = newnode;newnode->pevr = tail;newnode->next = cur;cur->pevr = newnode; }//尾删 void BPLSTPopBank(BPLSTNode** pphead) {//无节点的情况下不能删除assert(pphead);assert(*pphead);//只有头节点一个节点的情况下//直接释放处理if ((*pphead)->next == (*pphead)){(*pphead)->next = NULL;(*pphead)->pevr = NULL;free(*pphead);(*pphead) = NULL;return;}//有两个或两个以上节点的情况下进行找尾。BPLSTNode* cur = *pphead;BPLSTNode* pevr = *pphead;while (cur->next != (*pphead)){pevr = cur;cur = cur->next;}//进行释放链接cur->next = NULL;cur->pevr = NULL;free(cur);cur = NULL;pevr->next = (*pphead);(*pphead)->pevr = pevr; }//查找 BPLSTNode* BPLSTFand(BPLSTNode** pphead, DataType x) {//没有节点的情况无法插入assert(pphead);assert(*pphead);//存在节点的情况下遍历查找if ((*pphead)->data == x){return (*pphead);}BPLSTNode* cur = (*pphead)->next;while (cur != (*pphead)){if (cur->data == x){return cur;}}return NULL; }//在pos位置前插入 void BPLSTInsert(BPLSTNode** pphead, BPLSTNode* pos, DataType x) {//断言指针assert(pphead);//获取节点BPLSTNode* newnode = BPLSTSpace(x);//无节点的情况下且pos为NULL就是头插if ((*pphead) == NULL){if (pos == NULL){//头插BPLSTPushFront(pphead, x);}else{perror((*pphead) == NULL && pos != NULL);}return;}//存在节点的情况(头不为NULL的情况)if ((*pphead) != NULL && pos == NULL){perror((*pphead) != NULL && pos == NULL);return;}//正常可以插入的情况//pos为头节点的情况下if ((*pphead) == pos){//就是头插BPLSTPushFront(pphead, x);return;}//pos不为头的情况BPLSTNode* cur = *pphead;BPLSTNode* pevr = *pphead;while (cur != pos){pevr = cur;cur = cur->next;}//插入并链接pevr->next = newnode;newnode->pevr = pevr;newnode->next = pos;pos->pevr = newnode; }//在pos位置前删除 void BPLSTEaser(BPLSTNode** pphead, BPLSTNode* pos) {//无节点的情况下皆不可删除assert(pphead);assert(*pphead);//pos为空不能删除assert(pos);//查找pos是否是该链表中的节点//……………………省略………………//若pos为头节点if ((*pphead) == pos){//进行尾删BPLSTPopBank(pphead);return;}//pos不为头节点的情况//pos是头节点的下一个节点的情况if ((*pphead)->next == pos){//直接删除头BPLSTNode* pevr = (*pphead)->pevr;(*pphead)->next = NULL;(*pphead)->pevr = NULL;free(*pphead);pos->pevr = pevr;pevr->next = pos;*pphead = pos;return;}//pos即不为头节点也不是头节点的下一个节点的情况BPLSTNode* cur = *pphead;BPLSTNode* pevr = cur->pevr;//循环遍历找poswhile (cur->next != pos){pevr = cur;cur = cur->next;}cur->next = NULL;cur->pevr = NULL;free(cur);cur = NULL;pevr->next = pos;pos->pevr = pevr; }//在pos位置后插入 void BPLSTInsertAfter(BPLSTNode** pphead, BPLSTNode* pos, DataType x) {//断言指针assert(pphead);//不存在节点的情况if ((*pphead) == NULL){//pos为空的情况if (pos == NULL){//尾插BPLSTPushBank(pphead, x);}else //pos不为空的情况{//无法插入,直接断言assert(pos);}return;}//存在节点的情况//pos为NULL 无法插入if (pos == NULL){assert(pos);return;}//pos不为NULL的情况//获取节点BPLSTNode* newnode = BPLSTSpace(x);//进行插入链接BPLSTNode* next = pos->next;pos->next = newnode;newnode->pevr = pos;newnode->next = next;next->pevr = newnode; }//在pos位置后删除 void BPLSTEaserAfter(BPLSTNode** pphead, BPLSTNode* pos) {//不存在节点无法删除assert(pphead);assert(*pphead);//pos为空无法删除assert(pos);//pos为头节点if (pos == (*pphead)){//仅有头节点一个节点的情况if ((*pphead)->next == (*pphead)){(*pphead)->next = NULL;(*pphead)->pevr = NULL;free(*pphead);*pphead = NULL;}else{BPLSTNode* cur = pos->next;BPLSTNode* next = cur->next;cur->next = NULL;cur->pevr = NULL;free(cur);cur = NULL;pos->next = next;next->pevr = pos;}return;}//pos为尾节点的情况if (pos == (*pphead)->pevr){//仅有pos和头节点两个节点的情况if ((*pphead)->next == pos){(*pphead)->next = NULL;(*pphead)->pevr = NULL;free(*pphead);pos->next = pos;pos->pevr = pos;*pphead = pos;}else//具有三个节点的情况,且头节点的下一个节点不是pos{BPLSTNode* cur = pos->next;BPLSTNode* next = cur->next;cur->next = NULL;cur->pevr = NULL;free(cur);cur = NULL;pos->next = next;next->pevr = pos;*pphead = next;}return;}//pos不为尾的情况BPLSTNode* cur = pos->next;BPLSTNode* next = cur->next;cur->next = NULL;cur->pevr = NULL;free(cur);cur = NULL;pos->next = next;next->pevr = pos; }int main() {BPLSTNode* sl = NULL;//头插BPLSTPushFront(&sl, 1);BPLSTPushFront(&sl, 2);BPLSTPushFront(&sl, 3);BPLSTPrint(sl);//打印//头删BPLSTPopFront(&sl);BPLSTPopFront(&sl);BPLSTPrint(sl);//打印//尾插BPLSTPushBank(&sl, 5);BPLSTPushBank(&sl, 6);BPLSTPushBank(&sl, 7);BPLSTPrint(sl);//打印//尾删BPLSTPopBank(&sl);BPLSTPopBank(&sl);BPLSTPopBank(&sl);BPLSTPrint(sl);//打印//查找BPLSTNode* ret = BPLSTFand(&sl, 1);if (ret != NULL) printf("%d\n", ret->data);else printf("ret==NULL\n");//在pos位置前插入BPLSTInsert(&sl, ret, 5);BPLSTInsert(&sl, ret->pevr, 6);BPLSTPrint(sl);//打印//在pos位置前删除BPLSTEaser(&sl, ret->next);BPLSTPrint(sl);//打印ret = BPLSTFand(&sl, 5);if (ret != NULL) printf("%d\n", ret->data);else printf("ret==NULL\n");//在pos位置后插入BPLSTInsertAfter(&sl, ret, 7);BPLSTInsertAfter(&sl, ret, 8);BPLSTPrint(sl);//打印//在pos位置后删除BPLSTEaserAfter(&sl, ret);BPLSTPrint(sl);//打印ret = BPLSTFand(&sl, 6);if (ret != NULL) printf("%d\n", ret->data);else printf("ret==NULL\n");//在pos位置后删除BPLSTEaserAfter(&sl, ret);BPLSTPrint(sl);//打印BPLSTEaserAfter(&sl, ret);BPLSTPrint(sl);//打印BPLSTEaserAfter(&sl, ret);BPLSTPrint(sl);//打印return 0; }
双向带头循环链表
节点中存放数据以及两个指针,一个是指向前一个节点的指针,另一个是指向下一个节点的指针,会单独开辟一个节点空间用来做哨兵位的头节点,一般哨兵位头节点中不存放有效数据,且尾节点中指向下一个节点的指针存放的是哨兵位头节点的地址,哨兵位头节点中的指向前一个节点的指针存放的是尾节点的地址。
代码:
#define _CRT_DECURE_NO_WARNINGS 1#include <stdio.h> #include <stdlib.h> #include <assert.h>//创建结构 typedef int DataType;typedef struct BHPSTLNode {DataType data;struct BHPSTLNode* pevr;struct BHPSTLNode* next; }BHPSTLNode;//初始化哨兵位头节点 void BHPSTLInit(BHPSTLNode** pphead, DataType x) {//申请空间BHPSTLNode* newnode = (BHPSTLNode*)malloc(sizeof(BHPSTLNode));if (newnode == NULL){perror("malloc fail 12link");return;}//申请成功后进行赋值newnode->next = newnode;newnode->pevr = newnode;newnode->data = x;*pphead = newnode; }//打印 void BHPSTLPrint(BHPSTLNode* phead) {//空链表直接打印if (phead == NULL){printf("NULL\n");return;}//打印哨兵位的头节点printf("%d->", phead->data);BHPSTLNode* cur = phead->next;while (cur != phead){printf("%d->", cur->data);cur = cur->next;}printf("phead\n"); }//创建节点 BHPSTLNode* BHPSTLSpace(DataType x) {//创建节点BHPSTLNode* newnode = (BHPSTLNode*)malloc(sizeof(BHPSTLNode));if (newnode == NULL){perror("malloc fail 51 link");return NULL;}//创建成功进行链接newnode->data = x;newnode->next = NULL;newnode->pevr = NULL;return newnode; }//头插 void BHPSTLPushFront(BHPSTLNode** pphead, DataType x) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//创建节点BHPSTLNode* newnode = BHPSTLSpace(x);//直接进行插入BHPSTLNode* next = (*pphead)->next;(*pphead)->next = newnode;newnode->pevr = (*pphead);newnode->next = next;next->pevr = newnode; }//头删 void BHPSTLPopFront(BHPSTLNode** pphead) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//仅有哨兵位的头节点一个节点不能删除if ((*pphead)->pevr == (*pphead)){assert(NULL);}//具有两个及多个节点的情况//进行删除BHPSTLNode* cur = (*pphead)->next;BHPSTLNode* next = cur->next;cur->next = NULL;cur->pevr = NULL;free(cur);cur = NULL;(*pphead)->next = next;next->pevr = (*pphead); }//尾插 void BHPSTLPushBank(BHPSTLNode** pphead, DataType x) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//创建节点BHPSTLNode* newnode = BHPSTLSpace(x);//找尾BHPSTLNode* tail = (*pphead)->pevr;//插入tail->next = newnode;newnode->pevr = tail;newnode->next = (*pphead);(*pphead)->pevr = newnode; }//尾删 void BHPSTLPopBank(BHPSTLNode** pphead) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//仅有哨兵位的头节点一个节点无法删除if ((*pphead)->next == (*pphead)){assert(NULL);}//找尾和尾的前一个释放链接BHPSTLNode* tail = (*pphead)->pevr;BHPSTLNode* pevr = tail->pevr;tail->next = NULL;tail->pevr = NULL;free(tail);tail = NULL;pevr->next = (*pphead);(*pphead)->pevr = pevr; }//查找 BHPSTLNode* BHPSTLFind(BHPSTLNode* phead, DataType x) {//断言指针assert(phead);//循环遍历查找BHPSTLNode* cur = phead->next;while (cur != phead){if (cur->data == x){return cur;}cur = cur->next;}return NULL; }//在pos位置前插入 void BHPSTLInsert(BHPSTLNode** pphead, BHPSTLNode* pos, DataType x) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//若pos为空无法插入assert(pos);//判断pos是否存在于该链表中//………… 省略 …………//获取节点BHPSTLNode* newnode = BHPSTLSpace(x);BHPSTLNode* pevr = pos->pevr;pevr->next = newnode;newnode->pevr = pevr;newnode->next = pos;pos->pevr = newnode; }//在pos位置前删除 void BHPSTLErase(BHPSTLNode** pphead, BHPSTLNode* pos) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//pos为空无法删除assert(pos);//判断pos是否存在于该链表中//………… 省略 …………//若pos为哨兵位头节点的下一个节点//无法删除(即哨兵位的头节点无法删除)//若pos为哨兵位的头节点//且仅有头节点一个节点的情况无法删除if ((*pphead)->next == pos){assert(NULL);return;}//其余情况BHPSTLNode* cur = pos->pevr;BHPSTLNode* pevr = cur->pevr;cur->next = NULL;cur->pevr = NULL;free(cur);cur = NULL;pevr->next = pos;pos->pevr = pevr; }//在pos位置后插入 void BHPSTLInsertAfter(BHPSTLNode** pphead, BHPSTLNode* pos, DataType x) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//pos为空无法插入assert(pos);//判断pos是否存在于该链表中//………… 省略 …………//创建节点BHPSTLNode* newnode = BHPSTLSpace(x);BHPSTLNode* next = pos->next;pos->next = newnode;newnode->pevr = pos;newnode->next = next;next->pevr = newnode; }//在pos位置后删除 void BHPSTLEraseAfter(BHPSTLNode** pphead, BHPSTLNode* pos) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//pos为NULL不能删除assert(pos);//判断pos是否存在于该链表中//………… 省略 …………//若pos为尾节点无法删除//(尾节点的下一个节点是哨兵位的头节点)//若仅有哨兵位头节点一个节点//且pos为哨兵位头节点的情况无法删除if (pos->next == (*pphead)){assert(NULL);}//其余情况BHPSTLNode* cur = pos->next;BHPSTLNode* next = cur->next;cur->next = NULL;cur->pevr = NULL;free(cur);cur = NULL;pos->next = next;next->pevr = pos; }//销毁 void BHPSTLDestroy(BHPSTLNode** pphead) {//哨兵位的头节点必须存在assert(pphead);assert(*pphead);//循环遍历销毁BHPSTLNode* cur = (*pphead)->next;BHPSTLNode* next = (*pphead)->next;while (cur != (*pphead)){next = cur->next;cur->next = NULL;cur->pevr = NULL;free(cur);cur = next;}cur->pevr = NULL;cur->next = NULL;free(cur);cur = NULL;(*pphead) = NULL; }int main() {BHPSTLNode* sl = NULL;//初始化哨兵位头节点BHPSTLInit(&sl, 0);BHPSTLPrint(sl);//打印//头插BHPSTLPushFront(&sl, 1);BHPSTLPushFront(&sl, 2);BHPSTLPushFront(&sl, 3);BHPSTLPrint(sl);//打印//头删BHPSTLPopFront(&sl);BHPSTLPrint(sl);//打印BHPSTLPopFront(&sl);BHPSTLPrint(sl);//打印BHPSTLPopFront(&sl);BHPSTLPrint(sl);//打印//尾插BHPSTLPushBank(&sl, 5);BHPSTLPushBank(&sl, 6);BHPSTLPushBank(&sl, 7);BHPSTLPrint(sl);//打印//尾删BHPSTLPopBank(&sl);BHPSTLPrint(sl);//打印//BHPSTLPopBank(&sl);//BHPSTLPrint(sl);//打印//BHPSTLPopBank(&sl);//BHPSTLPrint(sl);//打印//查找BHPSTLNode* ret = BHPSTLFind(sl, 6);if (ret == NULL) printf("find: NULL\n");else printf("Find : %d\n", ret->data);//在pos位置前插入BHPSTLInsert(&sl, ret, 8);BHPSTLPrint(sl);//打印BHPSTLInsert(&sl, ret->pevr, 9);BHPSTLPrint(sl);//打印BHPSTLInsert(&sl, ret->pevr->pevr, 10);BHPSTLPrint(sl);//打印//在pos位置前删除BHPSTLErase(&sl, ret);BHPSTLPrint(sl);//打印BHPSTLErase(&sl, ret);BHPSTLPrint(sl);//打印BHPSTLErase(&sl, ret);BHPSTLPrint(sl);//打印BHPSTLErase(&sl, ret);BHPSTLPrint(sl);//打印//BHPSTLErase(&sl, sl);//BHPSTLPrint(sl);//打印//BHPSTLErase(&sl, sl);//BHPSTLPrint(sl);//打印//在pos位置后插入BHPSTLInsertAfter(&sl, ret, 9);BHPSTLPrint(sl);//打印BHPSTLInsertAfter(&sl, sl, 7);BHPSTLPrint(sl);//打印//在pos位置后删除BHPSTLEraseAfter(&sl, ret);BHPSTLPrint(sl);//打印//BHPSTLEraseAfter(&sl, ret->pevr);//BHPSTLPrint(sl);//打印BHPSTLEraseAfter(&sl, sl);BHPSTLPrint(sl);//打印BHPSTLEraseAfter(&sl, sl);BHPSTLPrint(sl);//打印//BHPSTLEraseAfter(&sl, sl);//BHPSTLPrint(sl);//打印//销毁BHPSTLDestroy(&sl);BHPSTLPrint(sl);//打印return 0; }
以上为自写8种链表代码,各位铁子欢迎讨论。