数据结构链表完整实现(负完整代码)


文章目录

  • 前言
  • 引入
  • 1、链表定义及结构
  • 链表的分类
  • 3、单向不带头链表实现
    • 实现
    • 完整代码
  • 4、带头双向循环链表实现
    • 实现
    • 完整代码


前言


引入

在上一篇文章中,我们认识了顺序表,但是在许多情况中,顺序表在处理一些事件时还存在许多问题,比如:

1.头插、头删或者在中部的插入或删除需要移动大量的元素,时间复杂度过高。

2.增容需要申请新空间,拷贝数据,释放旧空间,会有不小的消耗。

3.增容一般是呈2倍的增长,势必会有一定的空间浪费。例如当前容量为50,满了以后增容到 200,我们再继续插入了5个数据,后面没有数据插入了,那么就浪费了45个数据空间。

为了解决这些问题,我们提出了如下结构,链表。

1、链表定义及结构

概念:链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。

结构:列表中存在数据域与指针域,数据域用于存放该地区的值,指针域用于存放指向的下一个目标的地址。

typedef int SLTDataType;//single list
typedef struct SListNode {//数据域与指针域SLTDataType data;struct SListNode* next;
}SLTNode;

在这里插入图片描述

上面就是常见的单链表的结构:

1.链表在逻辑上连续,在物理上不连续

2.每一个新的区域都是动态申请出来的,申请出的区域可以连续也可以不连续

链表的分类

1.单向和双向链表

在这里插入图片描述

2.带头和不带头

在这里插入图片描述

3.循环或非循环

在这里插入图片描述

虽然链表的分类有很多,但在实际情况中,我们并不是都用的,比较常用的链表就是无头单向链表与带头双向循环链表。

无头单向链表

在这里插入图片描述

带头双向循环链表

在这里插入图片描述

以下,我们就来实现一下这两个链表

3、单向不带头链表实现

实现

1)结构定义:单向不带头链表分为指针域和数据域。其中指针域存放下一个位置的地址,数据域存放当前位置的值。

typedef int SLTDataType;//single list
typedef struct SListNode {//数据域与指针域SLTDataType data;struct SListNode* next;
}SLTNode;

2)尾插

//尾插
void SListPushBack(SLTNode** pphead,SLTDataType x)
{SLTNode* newNode = CreatNode(x);//指针未指向任何位置,表明链表中还没有值if (*pphead == NULL) {*pphead = newNode;}else {//新建一个临时节点,用于寻找最后一个节点SLTNode* cur = *pphead;//找最后一个节点(尾节点指向NULL位置)while (cur->next != NULL) {cur = cur->next;}//尾节点指针域存放新节点地址cur->next = newNode;}}

3)头插

//头插
void SListPushFront(SLTNode** pphead, SLTDataType x) {SLTNode* newNode = CreatNode(x);//让新节点指针域指向当前首节点newNode->next = *pphead;//新插入的节点变为了首节点*pphead = newNode;
}

4)尾删

//尾删
void SListPopBack(SLTNode** pphead) {//表里面没有值assert(*pphead);//表中只有一个值if ((*pphead)->next == NULL) {free(*pphead);*pphead = NULL;}//表中有一个或者一个以上的值else {SLTNode* cur = *pphead;SLTNode* prev = NULL;//找到尾节点和前一个节点while (cur->next != NULL) {prev = cur;cur = cur->next;}free(cur);cur = NULL;prev->next = NULL;}
}

5)头删

//头删
void SListPopFront(SLTNode** pphead) {assert(*pphead);//建立一个临时节点存储当前首节点指针域指向的地址,即第二个节点的地址SLTNode* cur = (*pphead)->next;//释放当前首节点的值free(*pphead);*pphead = NULL;//为首节点赋上第二个节点的值*pphead = cur;}

6)在位置前插入

//在pos前插入
void SListInsert(SLTNode** pphead,SLTNode* pos,SLTDataType x) {//pos位置就是首结点,就转换为头插if (pos == *pphead) {SListPushFront(pphead,x);}//pos位置是其他的节点else {SLTNode* newNode = CreatNode(x);SLTNode* prev = *pphead;while (prev->next != pos) {prev = prev->next;}//将前一个的指针域指向插入的值的地址:newNodeprev->next = newNode;//将新的值指针域指向pos位置newNode->next = pos;}}

7)在位置后插入

//在pos后插入
void SListInsertAfter(SLTNode** pphead, SLTNode* pos, SLTDataType x) {//建立一个新的节点SLTNode* newNode = CreatNode(x);//建立一个临时变量存储pos后面的节点SLTNode* after = pos->next;//让pos指向新节点pos->next = newNode;//让新节点指向刚刚pos后面的节点newNode->next = after;}

8)删除位置的值

//删除pos位置的值
void SListErase(SLTNode** pphead,SLTNode* pos) {//pos位置与首节点重合,转换为头删if (pos == *pphead) {SListPopFront(pphead);}else {SLTNode* prev = *pphead;//找pos的前一个位置while (prev->next != pos) {prev = prev->next;}//将前一个值指向pos的后一个值prev->next = pos->next;free(pos);pos = NULL;}}

9)删除位置后的值

//删除pos后面的值
void SListEraseAfter(SLTNode** pphead,SLTNode* pos) {//建立一个临时变量存储pos后两位的位置SLTNode* after = pos->next->next;free(pos->next);pos->next = NULL;//让pos指向刚刚后两位的位置pos->next = after;}

10)按值查找

//按值查找
SLTNode* SListFind(SLTNode* phead, SLTDataType x) {SLTNode* cur = phead;while (cur) {if (cur->data == x) {return cur;}cur = cur->next;}return NULL;
}

11)修改

//修改
void SListModify(SLTNode** pphead, SLTNode* pos,SLTDataType x) {pos->data = x;
}

12)保存

//保存
void SListSave(SLTNode* pphead) {FILE* pf = fopen("SListNode.txt","wb");if (pphead == NULL) {fclose(pf);pf = NULL;}else {SLTNode* cur = pphead;while (cur != NULL) {fwrite(cur,sizeof(SLTDataType),1,pf);cur = cur->next;}}}

13)打印

//打印
void SListPrint(SLTNode* phead) {SLTNode* cur = phead;if (cur == NULL) {//如果链表中无元素,则cur == NULL,不进入循环printf("NULL\n");}else {//一直遍历到最后一个位置:尾节点指向的NULL位置while (cur != NULL) {//打印数据printf("%d ", cur->data);//根据指针跳转到下一个位置cur = cur->next;}printf("\n");}
}

14)清空

//清空
void SListClear(SLTNode** pphead) {assert(*pphead);//清空链表,链表之后还要使用,所以我们只将首位置置为NULL,不释放//这里从第二个位置开始释放SLTNode* cur = (*pphead)->next;SLTNode* after = NULL;while (cur != NULL) {//先记录下一个节点的位置after = cur->next;//释放当前节点free(cur);cur = NULL;cur = after;}//清空链表,链表之后还要使用,所以我们只将首位置置为NULL,不释放*pphead = NULL;
}

15)销毁

//销毁
void SListDestroy(SLTNode** pphead) {assert(*pphead);//销毁链表,链表之后不能使用了,所以将首位置也一并释放SLTNode* cur = *pphead;SLTNode* after = NULL;while (cur != NULL) {//先记录下一个节点的位置after = cur->next;//释放当前节点free(cur);cur = NULL;cur = after;}
}

完整代码

1)SListNode.h

#pragma once#include<stdio.h>
#include<assert.h>
#include<stdlib.h>typedef int SLTDataType;//single list
typedef struct SListNode {//数据域与指针域SLTDataType data;struct SListNode* next;
}SLTNode;//打印
void SListPrint(SLTNode* phead);//头插
void SListPushFront(SLTNode** pphead, SLTDataType x);//尾插
void SListPushBack(SLTNode** pphead, SLTDataType x);//头删
void SListPopFront(SLTNode** pphead);//尾删
void SListPopBack(SLTNode** pphead);//按值查找
SLTNode* SListFind(SLTNode* phead, SLTDataType x);//在pos前插入
void SListInsert(SLTNode** pphead, SLTNode* pos, SLTDataType x);//在pos后插入
void SListInsertAfter(SLTNode** pphead, SLTNode* pos, SLTDataType x);//删除pos位置的值
void SListErase(SLTNode** pphead, SLTNode* pos);//删除pos后面的值
void SListEraseAfter(SLTNode** pphead, SLTNode* pos);//修改
void SListModify(SLTNode **pphead, SLTNode* pos, SLTDataType x);//保存
void SListSave(SLTNode* pphead);//清空
void SListClear(SLTNode** pphead);//销毁
void SListDestroy(SLTNode** pphead);

2)SListNode.c

#define _CRT_SECURE_NO_WARNINGS#include"SListNode.h"//打印
void SListPrint(SLTNode* phead) {SLTNode* cur = phead;if (cur == NULL) {//如果链表中无元素,则cur == NULL,不进入循环printf("NULL\n");}else {//一直遍历到最后一个位置:尾节点指向的NULL位置while (cur != NULL) {//打印数据printf("%d ", cur->data);//根据指针跳转到下一个位置cur = cur->next;}printf("\n");}
}//建立一个新的,可以长久储存的节点
SLTNode* CreatNode(SLTDataType x) {SLTNode* newnode = (SLTNode*)malloc(sizeof(SLTNode));if (newnode == NULL) {perror("malloc");return NULL;}newnode->data = x;newnode->next = NULL;return newnode;
}//尾插
void SListPushBack(SLTNode** pphead,SLTDataType x)
{SLTNode* newNode = CreatNode(x);//指针未指向任何位置,表明链表中还没有值if (*pphead == NULL) {*pphead = newNode;}else {//新建一个临时节点,用于寻找最后一个节点SLTNode* cur = *pphead;//找最后一个节点(尾节点指向NULL位置)while (cur->next != NULL) {cur = cur->next;}//尾节点指针域存放新节点地址cur->next = newNode;}}//头插
void SListPushFront(SLTNode** pphead, SLTDataType x) {SLTNode* newNode = CreatNode(x);//让新节点指针域指向当前首节点newNode->next = *pphead;//新插入的节点变为了首节点*pphead = newNode;
}//头删
void SListPopFront(SLTNode** pphead) {assert(*pphead);//建立一个临时节点存储当前首节点指针域指向的地址,即第二个节点的地址SLTNode* cur = (*pphead)->next;//释放当前首节点的值free(*pphead);*pphead = NULL;//为首节点赋上第二个节点的值*pphead = cur;}//尾删
void SListPopBack(SLTNode** pphead) {//表里面没有值assert(*pphead);//表中只有一个值if ((*pphead)->next == NULL) {free(*pphead);*pphead = NULL;}//表中有一个或者一个以上的值else {SLTNode* cur = *pphead;SLTNode* prev = NULL;//找到尾节点和前一个节点while (cur->next != NULL) {prev = cur;cur = cur->next;}free(cur);cur = NULL;prev->next = NULL;}
}//按值查找
SLTNode* SListFind(SLTNode* phead, SLTDataType x) {SLTNode* cur = phead;while (cur) {if (cur->data == x) {return cur;}cur = cur->next;}return NULL;
}//在pos前插入
void SListInsert(SLTNode** pphead,SLTNode* pos,SLTDataType x) {//pos位置就是首结点,就转换为头插if (pos == *pphead) {SListPushFront(pphead,x);}//pos位置是其他的节点else {SLTNode* newNode = CreatNode(x);SLTNode* prev = *pphead;while (prev->next != pos) {prev = prev->next;}//将前一个的指针域指向插入的值的地址:newNodeprev->next = newNode;//将新的值指针域指向pos位置newNode->next = pos;}}//在pos后插入
void SListInsertAfter(SLTNode** pphead, SLTNode* pos, SLTDataType x) {//建立一个新的节点SLTNode* newNode = CreatNode(x);//建立一个临时变量存储pos后面的节点SLTNode* after = pos->next;//让pos指向新节点pos->next = newNode;//让新节点指向刚刚pos后面的节点newNode->next = after;}//删除pos位置的值
void SListErase(SLTNode** pphead,SLTNode* pos) {//pos位置与首节点重合,转换为头删if (pos == *pphead) {SListPopFront(pphead);}else {SLTNode* prev = *pphead;//找pos的前一个位置while (prev->next != pos) {prev = prev->next;}//将前一个值指向pos的后一个值prev->next = pos->next;free(pos);pos = NULL;}}//删除pos后面的值
void SListEraseAfter(SLTNode** pphead,SLTNode* pos) {//建立一个临时变量存储pos后两位的位置SLTNode* after = pos->next->next;free(pos->next);pos->next = NULL;//让pos指向刚刚后两位的位置pos->next = after;}//修改
void SListModify(SLTNode** pphead, SLTNode* pos,SLTDataType x) {pos->data = x;
}//保存
void SListSave(SLTNode* pphead) {FILE* pf = fopen("SListNode.txt","wb");if (pphead == NULL) {fclose(pf);pf = NULL;}else {SLTNode* cur = pphead;while (cur != NULL) {fwrite(cur,sizeof(SLTDataType),1,pf);cur = cur->next;}}}//清空
void SListClear(SLTNode** pphead) {assert(*pphead);//清空链表,链表之后还要使用,所以我们只将首位置置为NULL,不释放//这里从第二个位置开始释放SLTNode* cur = (*pphead)->next;SLTNode* after = NULL;while (cur != NULL) {//先记录下一个节点的位置after = cur->next;//释放当前节点free(cur);cur = NULL;cur = after;}//清空链表,链表之后还要使用,所以我们只将首位置置为NULL,不释放*pphead = NULL;
}//销毁
void SListDestroy(SLTNode** pphead) {assert(*pphead);//销毁链表,链表之后不能使用了,所以将首位置也一并释放SLTNode* cur = *pphead;SLTNode* after = NULL;while (cur != NULL) {//先记录下一个节点的位置after = cur->next;//释放当前节点free(cur);cur = NULL;cur = after;}
}

3)Test.c

#define _CRT_SECURE_NO_WARNINGS
#include"SListNode.h"void menu() {printf("*******************************\n");printf("***1、头插     2、尾插      ***\n");printf("***3、头删     4、尾删      ***\n");printf("***5、打印     6、按值查找  ***\n");printf("***7、前插     8、后插      ***\n");printf("***9、删除     10、后删     ***\n");printf("***11、修改    12、保存     ***\n");printf("***13、清空    14、销毁     ***\n");printf("***-1、退出                 ***\n");printf("*******************************\n");
}enum {PushFront = 1,PushBack,PopFront,PopBack,Print,FindByValue,Insert,InsertAfter,Erase,EraseAfter,Modify,Save,Clear,Destroy,Exit = -1
};int main() {SLTNode* s = NULL;SLTDataType x;SLTNode* pos;int input = 0;do {menu();printf("请输入你想进行的操作:");scanf("%d", &input);switch (input) {case PushFront:printf("请输入你要插入的数据,以-1结束\n");do {scanf("%d", &x);if (x != -1){SListPushFront(&s,x);}} while (x != -1);break;case PushBack:printf("请输入你要插入的数据,以-1结束\n");do {scanf("%d", &x);if (x != -1){SListPushBack(&s,x);}} while (x != -1);break;case PopFront:SListPopFront(&s);break;case PopBack:SListPopBack(&s);break;case Print:SListPrint(s);break;case FindByValue:printf("请输入你想要查找的值:");scanf("%d", &x);pos = SListFind(s,x);if (pos == NULL) {printf("链表中没有这个值\n");}else {printf("找到了\n");}break;case Insert:printf("请输入你想要在哪个值前插入:");scanf("%d", &x);pos = SListFind(s,x);printf("请输入你想要插入的值:");scanf("%d", &x);if (pos == NULL) {printf("链表中没有这个值,请检查你输入的值是否正确\n");}else {SListInsert(&s, pos, x);}break;case InsertAfter:printf("请输入你想要在哪个值后插入:");scanf("%d", &x);pos = SListFind(s, x);printf("请输入你想要插入的值:");scanf("%d", &x);if (pos == NULL) {printf("链表中没有这个值,请检查你输入的值是否正确\n");}else {SListInsertAfter(&s, pos, x);}break;case Erase:printf("请输入你想要删除的值:");scanf("%d", &x);pos = SListFind(s, x);if (pos == NULL) {printf("链表中没有这个值,请检查你输入的值是否正确\n");}else {SListErase(&s, pos);}break;case EraseAfter:printf("请输入你想要删除哪个值之后的值:");scanf("%d", &x);pos = SListFind(s, x);if (pos == NULL) {printf("链表中没有这个值,请检查你输入的值是否正确\n");}else if (pos->next == NULL) {printf("这个值后已经没有值了,无法进行删除,请检查你输入的值是否正确\n");}else {SListEraseAfter(&s, pos);}break;case Modify:printf("请输入你想要修改的值:");scanf("%d", &x);pos = SListFind(s, x);printf("请输入修改后的值:");scanf("%d", &x);if (pos == NULL) {printf("链表中没有这个值,请检查你输入的值是否正确\n");}else {SListModify(&s, pos, x);}break;case Save:SListSave(s);break;case Clear:SListClear(&s);break;case Destroy:SListDestroy(&s);break;case Exit:break;default:printf("输入值错误,请重新输入\n");}} while (input != Exit);return 0;
}

4、带头双向循环链表实现

实现

1)结构定义:带头双向循环链表分为数据域、前指针域和后指针域。其中前指针域存放前一个位置的地址,后指针域存放后一个位置的地址。

typedef int LTDataType;typedef struct ListNode
{struct ListNode* next;struct ListNode* prev;LTDataType val;
}ListNode;

2)初始化头结点:创建一个头节点。前后指针域都指向自己,数据域不做处理。

//初始化创建头结点
ListNode* ListInit()
{ListNode* phead =ListCreate(0);//前指针域phead->next = phead;//后指针域phead->prev = phead;return phead;
}

3)插入

//创建新节点
ListNode* ListCreate(LTDataType x)
{//动态申请内存ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));if (newNode == NULL) {perror("malloc");}//赋值newNode->val = x;return newNode;
}//按位置插入
void ListInsert(ListNode* pos, LTDataType x){assert(pos);//建立新节点ListNode* newNode = ListCreate(x);//临时节点存储插入位置的前一个位置地址ListNode* prev = pos->prev;//将新节点后指针域存储插入位置地址newNode->next = pos;//将插入位置前指针域存储新节点位置pos->prev = newNode;//插入位置前一个位置的后指针域存储新节点位置prev->next = newNode;//将新节点前指针域存储插入位置前一个位置地址newNode->prev = prev;
}

4)删除

//按位置删除
void ListErase(ListNode* pos) {assert(pos);//创建临时节点存储插入位置前后节点地址ListNode* prev = pos->prev;ListNode* next = pos->next;//将前节点的后指针指向后节点prev->next = next;//将后节点的前指针指向前节点next->prev = prev;free(pos);pos = NULL;
}

5)头插

// 头插
void ListPushFront(ListNode* pHead, LTDataType x) {assert(pHead);ListInsert(pHead->next,x);
}

6)尾插

// 尾插
void ListPushBack(ListNode* pHead, LTDataType x) {assert(pHead);ListInsert(pHead,x);
}

7)头删

// 头删
void ListPopFront(ListNode* pHead) {assert(pHead);ListErase(pHead->next);
}

8)尾删

// 尾删
void ListPopBack(ListNode* pHead) {assert(pHead);ListErase(pHead->prev);
}

9)查找

//查找
ListNode* ListFind(ListNode* pHead, LTDataType x){assert(pHead);//新建临时节点作为首元素节点ListNode* tail = pHead->next;while (tail != pHead) {if (tail->val == x) {return tail;}tail = tail->next;}return NULL;
}

10)打印

//打印
void ListPrint(ListNode* pHead) {assert(pHead);if (pHead->next == pHead) {printf("表中无元素\n");return;}ListNode* tail = pHead->next;while (tail != pHead) {printf("%d ",tail->val);tail = tail->next;}printf("\n");
}

11)清空

//清空
void ListClear(ListNode* pHead) {assert(pHead);ListNode* tail = pHead->next;//依次对各个空间进行释放while (tail != pHead) {ListNode* next = tail->next;free(tail);tail = NULL;tail = next;}//修改头结点前后指针域pHead->next = tail;pHead->prev = tail;
}

12)销毁

//销毁
void ListDestory(ListNode* pHead) {assert(pHead);ListNode* tail = pHead->next;//依次对各个空间进行释放while (tail != pHead) {ListNode* next = tail->next;free(tail);tail = NULL;tail = next;}//释放头结点free(pHead);pHead = NULL;
}

完整代码

1)ListNode.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>typedef int LTDataType;typedef struct ListNode
{struct ListNode* next;struct ListNode* prev;LTDataType val;
}ListNode;// 创建返回链表的头结点.
ListNode* ListInit();
// 双向链表销毁
void ListDestory(ListNode* pHead);
// 双向链表打印
void ListPrint(ListNode* pHead);
// 双向链表尾插
void ListPushBack(ListNode* pHead, LTDataType x);
// 双向链表尾删
void ListPopBack(ListNode* pHead);
// 双向链表头插
void ListPushFront(ListNode* pHead, LTDataType x);
// 双向链表头删
void ListPopFront(ListNode* pHead);
// 双向链表查找
ListNode* ListFind(ListNode* pHead, LTDataType x);
// 双向链表在pos的前面进行插入
void ListInsert(ListNode* pos, LTDataType x);
// 双向链表删除pos位置的节点
void ListErase(ListNode* pos);
//清空
void ListClear(ListNode* pHead);
//打印
void ListPrint(ListNode* pHead);

2)ListNode.c

#define _CRT_SECURE_NO_WARNINGS#include"ListNode.h"//创建新节点
ListNode* ListCreate(LTDataType x)
{//动态申请内存ListNode* newNode = (ListNode*)malloc(sizeof(ListNode));if (newNode == NULL) {perror("malloc");}//赋值newNode->val = x;return newNode;
}//初始化创建头结点
ListNode* ListInit()
{ListNode* phead =ListCreate(0);//前指针域phead->next = phead;//后指针域phead->prev = phead;return phead;
}//查找
ListNode* ListFind(ListNode* pHead, LTDataType x){assert(pHead);//新建临时节点作为首元素节点ListNode* tail = pHead->next;while (tail != pHead) {if (tail->val == x) {return tail;}tail = tail->next;}return NULL;
}//按位置插入
void ListInsert(ListNode* pos, LTDataType x){assert(pos);//建立新节点ListNode* newNode = ListCreate(x);//临时节点存储插入位置的前一个位置地址ListNode* prev = pos->prev;//将新节点后指针域存储插入位置地址newNode->next = pos;//将插入位置前指针域存储新节点位置pos->prev = newNode;//插入位置前一个位置的后指针域存储新节点位置prev->next = newNode;//将新节点前指针域存储插入位置前一个位置地址newNode->prev = prev;
}//按位置删除
void ListErase(ListNode* pos) {assert(pos);//创建临时节点存储插入位置前后节点地址ListNode* prev = pos->prev;ListNode* next = pos->next;//将前节点的后指针指向后节点prev->next = next;//将后节点的前指针指向前节点next->prev = prev;free(pos);pos = NULL;
}//打印
void ListPrint(ListNode* pHead) {assert(pHead);if (pHead->next == pHead) {printf("表中无元素\n");return;}ListNode* tail = pHead->next;while (tail != pHead) {printf("%d ",tail->val);tail = tail->next;}printf("\n");
}//清空
void ListClear(ListNode* pHead) {assert(pHead);ListNode* tail = pHead->next;//依次对各个空间进行释放while (tail != pHead) {ListNode* next = tail->next;free(tail);tail = NULL;tail = next;}//修改头结点前后指针域pHead->next = tail;pHead->prev = tail;
}//销毁
void ListDestory(ListNode* pHead) {assert(pHead);ListNode* tail = pHead->next;//依次对各个空间进行释放while (tail != pHead) {ListNode* next = tail->next;free(tail);tail = NULL;tail = next;}//释放头结点free(pHead);pHead = NULL;
}// 尾插
void ListPushBack(ListNode* pHead, LTDataType x) {assert(pHead);ListInsert(pHead,x);
}
// 尾删
void ListPopBack(ListNode* pHead) {assert(pHead);ListErase(pHead->prev);
}
// 头插
void ListPushFront(ListNode* pHead, LTDataType x) {assert(pHead);ListInsert(pHead->next,x);
}
// 头删
void ListPopFront(ListNode* pHead) {assert(pHead);ListErase(pHead->next);
}

3)Test.c

#define _CRT_SECURE_NO_WARNINGS#include"ListNode.h"void TestList1()
{ListNode* plist = ListInit();ListPushBack(plist, 1);ListPushBack(plist, 2);ListPushBack(plist, 3);ListPushBack(plist, 4);ListPrint(plist);ListPushFront(plist, 0);ListPushFront(plist, -1);ListPrint(plist);ListPopFront(plist);ListPopFront(plist);ListPopFront(plist);ListPrint(plist);ListPopBack(plist);ListPrint(plist);ListNode* pos = ListFind(plist, 3);if (pos){// 查找,附带着修改的作用pos->val *= 10;printf("找到了,并且节点的值乘以10\n");}else{printf("没有找到\n");}ListPrint(plist);ListInsert(pos, 300);ListPrint(plist);ListErase(pos);ListPrint(plist);ListClear(plist);ListPrint(plist);ListDestory(plist);
}int main() {TestList1();return 0;
}

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

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

相关文章

鸿鹄电子招投标系统:企业战略布局下的采购寻源解决方案

在数字化采购领域&#xff0c;企业需要一个高效、透明和规范的管理系统。通过采用Spring Cloud、Spring Boot2、Mybatis等先进技术&#xff0c;我们打造了全过程数字化采购管理平台。该平台具备内外协同的能力&#xff0c;通过待办消息、招标公告、中标公告和信息发布等功能模块…

数据分析——快递电商

一、任务目标 1、任务 总体目的——对账 本项目解决同时使用多个快递发货&#xff0c;部分隔离区域出现不同程度涨价等情形下&#xff0c;如何快速准确核对账单的问题。 1、在订单表中新增一列【运费差异核对】来表示订单运费实际有多少差异&#xff0c;结果为数值。 2、将…

【无标题】关于异常处理容易犯的错

一般项目是方法打上 try…catch…捕获所有异常记录日志&#xff0c;有些会使用 AOP 来进行类似的“统一异常处理”。 其实&#xff0c;这种处理异常的方式非常不可取。那么今天&#xff0c;我就和你分享下不可取的原因、与异常处理相关的坑和最佳实践。 捕获和处理异常容易犯…

Feature Fusion for Online Mutual KD

paper&#xff1a;Feature Fusion for Online Mutual Knowledge Distillation official implementation&#xff1a;https://github.com/Jangho-Kim/FFL-pytorch 本文的创新点 本文提出了一个名为特征融合学习&#xff08;Feature Fusion Learning, FFL&#xff09;的框架&…

行走在深度学习的幻觉中:问题缘由与解决方案

如何解决大模型的「幻觉」问题&#xff1f; 我们在使用深度学习大模型如LLM&#xff08;Large Language Models&#xff09;时&#xff0c;可能会遇到一种被称为“幻觉”的现象。没错&#xff0c;它并不是人脑中的错觉&#xff0c;而是模型对特定模式的过度依赖&#xff0c;这…

Linux---gcc编译

目录 前言 一、gcc编译 二、程序的编译过程 三、gcc查看编译过程 1.预处理阶段 2.编译 3.汇编 4.链接 动静态库链接的内容 动静态库链接的优缺点 5.总结记忆 前言 在前面我们学会使用vim对文件进行编辑&#xff0c;如果是C或者C程序&#xff0c;我们编辑好了内容…

【DDR】基于Verilog的DDR控制器的简单实现(一)——初始化

在FPGA中&#xff0c;大规模数据的存储常常会用到DDR。为了方便用户使用&#xff0c;Xilinx提供了DDR MIG IP核&#xff0c;用户能够通过AXI接口进行DDR的读写访问&#xff0c;然而MIG内部自动实现了许多环节&#xff0c;不利于用户深入理解DDR的底层逻辑。 本文以美光(Micro…

【算法刷题】Day28

文章目录 1. 买卖股票的最佳时机 III题干&#xff1a;算法原理&#xff1a;1. 状态表示&#xff1a;2. 状态转移方程3. 初始化4. 填表顺序5. 返回值 代码&#xff1a; 2. Z 字形变换题干&#xff1a;算法原理&#xff1a;1. 模拟2. 找规律 代码&#xff1a; 1. 买卖股票的最佳时…

重学Java 4 进制转换和位运算

天赋不好好使用的话&#xff0c;可是会被收回的哦 ——24.1.13 一、进制转换 1.常用的进制 2.十进制和二进制之间的转换 1.十进制转二进制 辗转相除法——循环除以2&#xff0c;取余数&#xff0c;除到商为0为止&#xff0c;除完后&#xff0c;由下往上&#xff0c;得出换算后…

JVM基础(7)——ParNew垃圾回收器

作者简介&#xff1a;大家好&#xff0c;我是smart哥&#xff0c;前中兴通讯、美团架构师&#xff0c;现某互联网公司CTO 联系qq&#xff1a;184480602&#xff0c;加我进群&#xff0c;大家一起学习&#xff0c;一起进步&#xff0c;一起对抗互联网寒冬 学习必须往深处挖&…

Kafka(四)Broker

目录 1 配置Broker1.1 Broker的配置broker.id0listererszookeeper.connectlog.dirslog.dir/tmp/kafka-logsnum.recovery.threads.per.data.dir1auto.create.topics.enabletrueauto.leader.rebalance.enabletrue, leader.imbalance.check.interval.seconds300, leader.imbalance…

Redis之集群方案比较

哨兵模式 在redis3.0以前的版本要实现集群一般是借助哨兵sentinel工具来监控master节点的状态&#xff0c;如果master节点异常&#xff0c;则会做主从切换&#xff0c;将某一台slave作为master&#xff0c;哨兵的配置略微复杂&#xff0c;并且性能和高可用性等各方面表现一般&a…

Node.js和npm

目录 01_Node.js01.什么是 Node.js目标讲解小结 02.fs模块-读写文件目标讲解小结 03.path模块-路径处理目标讲解小结 04.案例-压缩前端html目标讲解小结 05.认识URL中的端口号目标讲解小结 06.http模块-创建Web服务目标讲解小结 07.案例-浏览时钟目标讲解小结 02_Node.js模块化…

【LabVIEW FPGA入门】使用CompactRIO进行SPI和I2C通信

NI提供了 SPI and I2C Driver API&#xff1a;下载SPI and I2C Driver API - NI 该API使用FPGA数字I / O线与SPI或I2C设备进行通信。 选择数字硬件时&#xff0c;要考虑三个选项&#xff1a; NI Single-Board RIO硬件可同时使用SPI和I2C驱动程序。NI 9401 C系列模块与SPI驱动程…

LINUX网络

一、网络配置命令 1.1 ifconfig 命令功能ifconfig默认显示活动的显卡ifconfig -a显示所有的网卡ifconfig 网卡名称只显示前面的网卡信息ifconfig 网卡 down/ifdown 网卡关闭网卡ifconfig 网卡 up/ifup 网卡开启网卡ifconfig ens33:0 IP地址/子网掩码设置虚拟网卡 TYPEEthernet…

如何使用创建时间给文件重命名,简单的批量操作教程

在处理大量文件时&#xff0c;有时要按照规则对文件重命名&#xff0c;根据文件的创建时间来重命名。那如何批量操作呢&#xff1f;现在一起来看云炫文件管理器如何用文件的创建时间来批量重命名。 按创建时间重命名文件的前后对比图。 用创建时间批量给文件重命名的步骤&…

P1328 [NOIP2014 提高组] 生活大爆炸版石头剪刀布————C++

目录 [NOIP2014 提高组] 生活大爆炸版石头剪刀布题目背景题目描述输入格式输出格式样例 #1样例输入 #1样例输出 #1 样例 #2样例输入 #2样例输出 #2 提示 解题思路Code调用函数的Code&#xff08;看起来简洁一点&#xff09;运行结果 [NOIP2014 提高组] 生活大爆炸版石头剪刀布 …

人工智能_机器学习092_使用三维瑞士卷数据_利用分层聚类算法进行瑞士卷数据三维聚类---人工智能工作笔记0132

然后我们使用分层聚类算法来对我们导入的瑞士卷数据进行聚类 agg =AgglomerativeClustering(n_clusters = 6,linkage = ward) 可以看到这里我们使用的,聚类距离计算用的是,ward这种,最小化簇内方差的形式,l进行聚类对吧 可以看到这个linkage参数有好几个选择对吧,是之前我们讲过…

【Go】excelize库实现excel导入导出封装(三),基于excel模板导出excel

前言 大家好&#xff0c;这里是符华~ 关于excelize库实现excel导入导出封装&#xff0c;我已经写了两篇了&#xff0c;我想要的功能基本已经实现了&#xff0c;现在还差一个模板导出&#xff0c;这篇文章就来讲讲如何实现用模板导出excel。 前两篇&#xff1a; 【Go】excel…

Redis原理篇(Dict的收缩扩容机制和渐进式rehash)

Dict&#xff08;即字典&#xff09; Redis是一种键值型数据库&#xff0c;其中键与值的映射关系就是Dict实现的。 Dict通过三部分组成&#xff1a;哈希表&#xff08;DictHashTable&#xff09;&#xff0c;哈希节点(DictEntry)&#xff0c;字典&#xff08;Dict&#xff09…