链表续-8种链表(数据结构)

了解链表

由于之前已经有一篇文章介绍链表,本次直接上八种链表的代码

具体前一篇文章阅读此处链表介绍

八种链表代码

单向链表

节点当中存放数据以及指向下一个节点的指针

代码:

#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种链表代码,各位铁子欢迎讨论。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/59955.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何确保爬取的数据准确性和完整性?

在数据驱动的业务环境中&#xff0c;爬虫程序的准确性和完整性至关重要。本文将探讨如何使用Java编写爬虫程序&#xff0c;并确保其在爬取数据时的准确性和完整性。 1. 精确的HTML解析 确保数据准确性的第一步是精确地解析HTML。Jsoup是Java中常用的HTML解析库&#xff0c;它提…

关于Web Component

2024年8月14日 引言 Web Component 是一种用于构建可复用用户界面组件的技术&#xff0c;开发者可以创建自定义的 HTML 标签&#xff0c;并将其封装为包含逻辑和样式的独立组件&#xff0c;从而在任何 Web 应用中重复使用&#xff0c;并且可以做到无框架跨框架。 不同于 Vue…

【MySql】实验十六 综合练习:图书管理系统数据库结构

文章目录 创建图书管理系统数据库结构一、创建数据表1.1 book表1.2 reader表1.3 borrow表 二、插入示例数据2.1 向book表插入数据2.2 向reader表插入数据2.3 向borrow表插入数据 三、查询操作3.1 根据语义为借书表borrow的bno列和 rno列建立外键3.2 查询张小海编写的“数据库原…

AutoDL部署视觉大模型llama3.2-vision,从视频中寻找特定目标

注&#xff1a; windows11系统。示例为此项目&#xff1a;https://github.com/win4r/VideoFinder-Llama3.2-vision-Ollama 在当今的人工智能领域&#xff0c;深度学习模型的计算需求日益增长&#xff0c;特别是在处理复杂的视觉任务时&#xff0c;强大的算力往往是实现高效应用…

SHELL笔记(条件测试)

基本概念&#xff1a; 条件测试用于在 Shell 脚本中对各种条件进行判断&#xff0c;根据判断结果来决定是否执行特定的命令或代码块。条件测试可以用于比较数值、字符串&#xff0c;检查文件或目录的属性&#xff0c;以及判断命令的执行结果等。 格式&#xff1a; 格式1&…

JDK、MAVEN与IDEA的安装与配置

1.认识JDK、MAVEN与IDEA JDK 提供了编译和运行Java程序的基本环境。Maven 帮助管理项目的构建和依赖。IDEA 提供了一个强大的开发环境&#xff0c;使得编写、调试和运行Java程序更加高效。 2. 安装与环境配置 2.1 官网地址 选择你需要的版本下载&#xff1a; MAVEN下载传送…

微信小程序-prettier 格式化

一.安装prettier插件 二.配置开发者工具的设置 配置如下代码在setting.json里&#xff1a; "editor.formatOnSave": true,"editor.defaultFormatter": "esbenp.prettier-vscode","prettier.documentSelectors": ["**/*.wxml"…

【Mac】未能完成该操作 Unable to locate a Java Runtime

重生之我做完产品经理之后回来学习Data Mining Mac打开weka.jar报错"未能完成该操作 Unable to locate a Java Runtime" 1. 打开终端执行 java -version 指令&#xff0c;原来是没安装 JDK 环境 yyzccnn-mac ~ % java -version The operation couldn’t be comple…

【ArcGIS微课1000例】0127:计算城市之间的距离

本文讲述,在ArcGIS中,计算城市(以地级城市为例)之间的距离,效果如下图所示: 一、数据准备 加载配套实验数据包中的地级市和行政区划矢量数据(订阅专栏后,从私信查收数据),如下图所示: 二、计算距离 1. 计算邻近表 ArcGIS提供了计算点和另外点之间距离的工具:分析…

【WPF】Prism学习(五)

Prism Commands 1.错误处理&#xff08;Error Handling&#xff09; Prism 9 为所有的命令&#xff08;包含AsyncDelegateCommand&#xff09;提供了更好的错误处理。 避免用try/catch包装每一个方法根据不同遇到的异常类型来提供特定的逻辑处理可以在多个命令之间共享错误处…

【element-tiptap】Tiptap编辑器核心概念----结构篇

core-concepts 前言&#xff1a;这篇文章来介绍一下 Tiptap 编辑器的一些核心概念 &#xff08;一&#xff09;结构 1、 Schemas 定义文档组成方式。一个文档就是标题、段落以及其他的节点组成的一棵树。 每一个 ProseMirror 的文档都有一个与之相关联的 schema&#xff0c;…

2024.6使用 UMLS 集成的基于 CNN 的文本索引增强医学图像检索

Enhancing Medical Image Retrieval with UMLS-Integrated CNN-Based Text Indexing 问题 医疗图像检索中&#xff0c;图像与相关文本的一致性问题&#xff0c;如患者有病症但影像可能无明显异常&#xff0c;影响图像检索系统准确性。传统的基于文本的医学图像检索&#xff0…

初识Linux · 信号处理 · 续

目录 前言&#xff1a; 可重入函数 重谈进程等待和优化 前言&#xff1a; 在前文&#xff0c;我们已经介绍了信号产生&#xff0c;信号保存&#xff0c;信号处理的主题内容&#xff0c;本文作为信号处理的续篇&#xff0c;主要是介绍一些不那么重要的内容&#xff0c;第一个…

微信小程序 最新获取用户头像以及用户名

一.在小程序改版为了安全起见 使用用户填写来获取头像以及用户名 二.代码实现 <view class"login_box"><!-- 头像 --><view class"avator_box"><button wx:if"{{ !userInfo.avatarUrl }}" class"avatorbtn" op…

WPF MVVM框架

一、MVVM简介 MVC Model View Control MVP MVVM即Model-View-ViewModel&#xff0c;MVVM模式与MVP&#xff08;Model-View-Presenter&#xff09;模式相似&#xff0c;主要目的是分离视图&#xff08;View&#xff09;和模型&#xff08;Model&#xff09;&#xff0c;具有低…

【算法】【优选算法】前缀和(下)

目录 一、560.和为K的⼦数组1.1 前缀和1.2 暴力枚举 二、974.和可被K整除的⼦数组2.1 前缀和2.2 暴力枚举 三、525.连续数组3.1 前缀和3.2 暴力枚举 四、1314.矩阵区域和4.1 前缀和4.2 暴力枚举 一、560.和为K的⼦数组 题目链接&#xff1a;560.和为K的⼦数组 题目描述&#x…

两大新兴开发语言大比拼:Move PK Rust

了解 Move 和 Rust 的差异有助于开发者根据项目的具体需求选择最合适的语言。选择不恰当的语言可能会导致项目后期出现技术债务。不同语言有其独特的优势。了解 Move 和 Rust 的差异可以帮助开发者拓展技术视野&#xff0c;发现不同语言在不同领域的应用潜力。 咱们直奔主题&a…

Scaling Law的“终结“还是新起点?——开源实践者的深度思考

作者&#xff1a;宋大宝&#xff0c;与大宝同学因那篇《回顾总结展望「融合RL与LLM思想&#xff0c;探寻世界模型以迈向AGI」》结识于今年春天&#xff0c;虽我们当时某些思想观念有些出入&#xff0c;也碰撞出了很多火花与共鸣&#xff0c;并持续地相互启发的走到了现在。他是…

“fc-async”提供了基本的异步处理能力

在开发中,异步处理已经成为提升系统性能和用户体验的常用方式。然而,传统的@Async注解和基础的异步处理工具在面对复杂的任务场景时,存在局限性。这些局限性包括但不限于高并发环境下的稳定性、任务失败后的恢复机制、以及任务的监控和管理。 开源项目“fc-async”提供了基…

Ubuntu 的 ROS 操作系统 turtlebot3 导航仿真

引言 导航仿真是机器人自动化系统中不可或缺的一部分&#xff0c;能够帮助开发者在虚拟环境中测试机器人在复杂场景下的运动与路径规划。 在 Gazebo 仿真环境中&#xff0c;TurtleBot3 配合 ROS 操作系统提供了强大的导航功能。在进行导航仿真时&#xff0c;首先需要准备地图&…