链表续-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.rhkb.cn/news/476136.html

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

相关文章

Elastic 和 Red Hat:加速公共部门 AI 和机器学习计划

作者&#xff1a;来自 Elastic Michael Smith 随着公共部门组织适应数据的指数级增长&#xff0c;迫切需要强大、适应性强的解决方案来管理和处理大型复杂数据集。人工智能 (Artificial intelligence - AI) 和机器学习 (machine learning - ML) 已成为政府机构将数据转化为可操…

SAP B1 登陆报错解决方案 - 系统架构目录服务器选择

背景 登录时出现如下报错&#xff0c;报错显示为【系统架构目录服务器选择】 强行登录会发现过往账套都不见了 出现原因 出于各种原因在开机时没有把 SAP 所有的服务成功启动&#xff08;上一次启动科学上网后全局代理没关干净之类的&#xff09;。 解决方案 关机几分钟重启…

基于深度卷积神经网络(CNN)模型的图像着色研究与应用系统实现

1.摘要 许多历史照片都是黑白的&#xff0c;通过颜色化可以恢复这些照片的历史感和真实感&#xff0c;使人们更好地理解和感受历史事件。随着深度学习技术的发展&#xff0c;特别是卷积神经网络和自监督学习的兴起&#xff0c;研究人员提出了新的方法来解决这些问题。通过将颜色…

【CVE-2024-9413】SCP-Firmware漏洞:安全通告

安全之安全(security)博客目录导读 目录 一、概述 二、修订历史 三、CVE根因分析 四、问题修复解决 一、概述 在SCP固件中发现了一个漏洞&#xff0c;如果利用该漏洞&#xff0c;可能会允许应用处理器&#xff08;AP&#xff09;在系统控制处理器&#xff08;SCP&#xf…

Oracle 19C 安装RAC磁盘投票失败

ORACLE 19C 安装RAC第二个节点报错&#xff0c;没有找到足够的 voting 文件&#xff08;投票磁盘&#xff09; 1、磁盘投票失败分析 1.1、02节点报错日志 CRS-4123: Starting Oracle High Availability Services-managed resources CRS-2672: Attempting to start ora.mdnsd…

【Maven】IDEA创建Maven项目 Maven配置

文章目录 简介配置环境变量配置仓库测试安装 IDEA创建项目pom.xml 简介 Maven 是一个非常流行的项目管理和构建自动化工具&#xff0c;主要应用于 Java 项目的构建、依赖管理和项目信息管理。它是由 Apache 软件基金会维护的开源项目。Maven 的设计理念是通过一个项目对象模型…

vue3:使用插件递归组件

vue3:使用插件递归组件 首先安装插件 npm i unplugin-vue-define-optionsvite.config.ts 配置插件 // vite.config.ts// 引入 unplugin-vue-define-options import DefineOptions from "unplugin-vue-define-options"; export default defineConfig({// 注册插件 De…

开源TTS语音克隆神器GPT-SoVITS_V2版本地整合包部署与远程使用生成音频

文章目录 前言1.GPT-SoVITS V2下载2.本地运行GPT-SoVITS V23.简单使用演示4.安装内网穿透工具4.1 创建远程连接公网地址 5. 固定远程访问公网地址 前言 本文主要介绍如何在Windows系统电脑使用整合包一键部署开源TTS语音克隆神器GPT-SoVITS&#xff0c;并结合cpolar内网穿透工…

Keil+VSCode优化开发体验

目录 一、引言 二、详细步骤 1、编译器准备 2、安装相应插件 2.1 安装C/C插件 2.2 安装Keil相关插件 3、添加keil环境变量 4、加载keil工程文件 5、VSCode中成功添加工程文件后可能出现的问题 5.1 编码不一致问题 6、在VSCode中进行编译工程以及烧录程序 7、效果展示…

Llama模型文件介绍

文章目录 概要文件组成 概要 在使用 LLaMA&#xff08;Large Language Model Meta AI&#xff09;权重时&#xff0c;通常会涉及到与模型权重存储和加载相关的文件。这些文件通常是以二进制格式存储的&#xff0c;具有特定的结构来支持高效的模型操作。以下以Llama-7B为例&…

Spring Web入门练习

加法计算器 约定前后端交互接⼝ 约定 "前后端交互接⼝" 是进⾏ Web 开发中的关键环节. 接⼝⼜叫 API&#xff08;Application Programming Interface), 我们⼀般讲到接⼝或者 API&#xff0c;指的都是同⼀个东西. 是指应⽤程序对外提供的服务的描述, ⽤于交换信息…

Easyexcel(5-自定义列宽)

相关文章链接 Easyexcel&#xff08;1-注解使用&#xff09;Easyexcel&#xff08;2-文件读取&#xff09;Easyexcel&#xff08;3-文件导出&#xff09;Easyexcel&#xff08;4-模板文件&#xff09;Easyexcel&#xff08;5-自定义列宽&#xff09; 注解 ColumnWidth Data…

FIFO和LRU算法实现操作系统中主存管理

FIFO&#xff0c;用数组实现 1和2都是使用nextReplace实现新页面位置的更新 1、不精确时间&#xff1a;用ctime输出运行时间都是0.00秒 #include <iostream> #include <iomanip> #include<ctime>//用于计算时间 using namespace std;// 页访问顺序 int pa…

Unity3d场景童话梦幻卡通Q版城镇建筑植物山石3D模型游戏美术素材

注明&#xff1a;网络素材&#xff0c;仅供学习使用&#xff01; https://download.csdn.net/download/elineSea/90017291

batchnorm与layernorn的区别

1 原理 简单总结&#xff1a; batchnorn 和layernorm是在不同维度上对特征进行归一化处理。 batchnorm在batch这一维度上&#xff0c; 对一个batch内部所有样本&#xff0c; 在同一个特征通道上进行归一化。 举个例子&#xff0c; 假设输入的特征图尺寸为16x224x224x256&…

SpringAOP模拟实现

文章目录 1_底层切点、通知、切面2_切点匹配3_从 Aspect 到 Advisor1_代理创建器2_代理创建时机3_Before 对应的低级通知 4_静态通知调用1_通知调用过程2_模拟 MethodInvocation 5_动态通知调用 1_底层切点、通知、切面 注意点&#xff1a; 底层的切点实现底层的通知实现底层的…

标准驱动开发(Linux2.6(cdev) 的开发)

Linux2.6&#xff08;cdev&#xff09; 的开发 目录 Linux2.6&#xff08;cdev&#xff09; 的开发 回顾 Linux2.6&#xff08;cdev&#xff09; 的开发 了解一下 Linux2.6 开发框架 学习 Linux2.6 的相关接口 1、申请设备号&#xff08;alloc_chrdev_region&#xff09…

硬件知识 cadence16.6 原理图输出为pdf 网络名下划线偏移 (ORCAD)

1. cadence原理图输出为PDF网络名下划线偏移 生这种情况的原因 1. 设计的原理图图纸大小比正常的 A4图纸大。 2. 打印为PDF 的时候&#xff0c;打印机的设置有问题。 2.cadence原理图输出为 PDF网络名下划线偏移的情况 可以看到上图&#xff0c;网络名往上漂移。 3. 解决办法 …

HarmonyOs DevEco Studio小技巧31--卡片的生命周期与卡片的开发

Form Kit简介 Form Kit&#xff08;卡片开发服务&#xff09;提供一种界面展示形式&#xff0c;可以将应用的重要信息或操作前置到服务卡片&#xff08;以下简称“卡片”&#xff09;&#xff0c;以达到服务直达、减少跳转层级的体验效果。卡片常用于嵌入到其他应用&#xff0…

SSRF漏洞利用

2.漏洞利用 2.1 SSRF中URL的伪协议 file:// 从⽂件系统中获取⽂件内容&#xff0c;如&#xff0c;file:///etc/passwd dict:// 字典服务器协议&#xff0c;访问字典资源&#xff0c;如dict://ip:6379/info sftp:// ssh⽂件传输协议或安全⽂件传输协议 ldap:// 轻量级⽬录访问…