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


文章目录

  • 前言
  • 引入
  • 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.mzph.cn/news/620002.shtml

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

相关文章

【书生·浦语】大模型实战营——第四课笔记

教程链接&#xff1a;https://github.com/InternLM/tutorial/blob/main/xtuner/README.md 视频链接&#xff1a;https://www.bilibili.com/video/BV1yK4y1B75J/?vd_source5d94ee72ede352cb2dfc19e4694f7622 本次视频的内容分为以下四部分&#xff1a; 目录 微调简介 微调会使…

计算机体系结构----存储系统

本文严禁转载&#xff0c;仅供学习使用。参考资料来自中国科学院大学计算机体系结构课程PPT以及《Digital Design and Computer Architecture》、《超标量处理器设计》、同济大学张晨曦教授资料。如有侵权&#xff0c;联系本人修改。 1.1 引言 1.1.1虚拟和物理内存 程序员看到…

【科研技巧】如何判断某个期刊是什么类别及影响因子?是否是顶会?如何期刊内检索?AI写综述?AI做PPT?

相关链接 查找和免费下载文献的方式汇总国内外各大期刊关系、如何查看期刊等级以及查看某篇论文属于哪个期刊登录和访问EI(Engineering Village)数据库查找文献 1 如何判断某个期刊是什么类别及影响因子 https://sci.justscience.cn/ IFold是影响因子 期刊类别为SCIE、查看…

(收藏)数据治理:一文讲透数据安全

数据治理&#xff1a;一文讲透数据安全 数据安全是数据治理的核心内容之一&#xff0c;随着数据治理的深入&#xff0c;我不断的碰到数据安全中的金发姑娘问题&#xff08;指安全和效率的平衡&#xff09;。 DAMA说&#xff0c;降低风险和促进业务增长是数据安全活动的主要…

ssm基于JAVA的酒店客房管理系统论文

摘 要 现代经济快节奏发展以及不断完善升级的信息化技术&#xff0c;让传统数据信息的管理升级为软件存储&#xff0c;归纳&#xff0c;集中处理数据信息的管理方式。本酒店客房管理系统就是在这样的大环境下诞生&#xff0c;其可以帮助管理者在短时间内处理完毕庞大的数据信息…

IT从业人员如何养生?

目前&#xff0c;电脑对人体生理和心理方面的负面影响已日益受到人们的重视。为此科学使用电脑&#xff0c;减少电脑和网络的危害是十分必要的。好代码网总结了一些it从业人员的保健知识&#xff0c;分享给大家。 一是要增强自我保健意识 工作间隙注意适当休息&#xff0c;一般…

构建中国人自己的私人GPT-有道GPT

创作不易&#xff0c;请大家多鼓励支持。 在现实生活中&#xff0c;很多人的资料是不愿意公布在互联网上的&#xff0c;但是我们又要使用人工智能的能力帮我们处理文件、做决策、执行命令那怎么办呢&#xff1f;于是我们构建自己或公司的私人GPT变得非常重要。 先看效果 一、…

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

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

【LeetCode:30. 串联所有单词的子串 | 滑动窗口 + 哈希表】

&#x1f680; 算法题 &#x1f680; &#x1f332; 算法刷题专栏 | 面试必备算法 | 面试高频算法 &#x1f340; &#x1f332; 越难的东西,越要努力坚持&#xff0c;因为它具有很高的价值&#xff0c;算法就是这样✨ &#x1f332; 作者简介&#xff1a;硕风和炜&#xff0c;…

【踩坑】flask_uploads报错cannot import name ‘secure_filename‘

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 背景说明 截至目前&#xff0c;用新版的flask实现文件上传(用到flask_uploads库)&#xff0c;会出现这个问题。 问题原因 版本问题&#xff0c;新的werkzeug已经把secure_filename的位置改了。 解决方法 手动修改…

绘制几何图形(Shape)

目录 1、创建绘制组件 2、形状视口viewport 3、自定义样式 4、场景示例 绘制组件用于在页面绘制图形&#xff0c;Shape组件是绘制组件的父组件&#xff0c;父组件中会描述所有绘制组件均支持的通用属性。具体用法请参考Shape。 1、创建绘制组件 绘制组件可以由以下两种形式…

【Python机器学习】分类器的不确定估计——预测概率

predict_proba的输出是每个类别的概率&#xff0c;通常比decision_function的输出更容易理解&#xff0c;对于二分类问题&#xff0c;它的形状始终是(n_samples,2)。 import mglearn.tools from sklearn.ensemble import GradientBoostingClassifier from sklearn.datasets im…

Vue-16、Vue列表渲染(v-for的使用)

1、vue遍历数组 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>列表渲染</title><script type"text/javascript" src"https://cdn.jsdelivr.net/npm/vue2/dist/vue.js"…

C#基础-空处理

在c#中&#xff0c;值对象是没有办法赋值为null的。比如说&#xff0c;你想要定义一个布尔值&#xff0c;你的赋值数据要么得是true、要么就得是false&#xff0c;默认情况下我们永远没可能给这个布尔赋值为null&#xff0c;即使只是对这个变量进行声明而不初始化数据&#xff…

不方便拉网线,房间又没Wifi信号?按照这个教程,让你家里每个角落都有网

前言 前段时间去了一个朋友家里&#xff0c;她老是和我叨叨说她家的卧室一点Wifi信号都没有。每次一躺床上都只能用手机流量上网。 家里明明有拉宽带&#xff0c;为什么在某一些地方还是得用自己手机流量&#xff1f;哎&#xff0c;有钱人的痛就是房子太大了。 我问她为啥不多…

【Maven】002-Maven 安装和配置

【Maven】002-Maven 安装和配置 文章目录 【Maven】002-Maven 安装和配置一、官网1、官网2、历史版本列表3、Maven 仓库地址 二、下载 Maven 3.8.8 版本1、进入 Maven 3.8.8 版本发行说明页2、进入下载页3、下载4、下载得到 apache-maven-3.8.8-bin.zip 三、Maven 安装1、将安装…

jenkins环境搭建

jenkins环境搭建 1.环境说明2.环境准备1.jdk安装2.安装Git3.安装sshpass4.安装Maven 3.安装Jenkins(war包方式安装)1.安装2.镜像加速 4.官网提供的yum方式安装5.访问 1.环境说明 keyvalue环境centos7jdk版本11git2.43.0maven3.9.6jenkins最新版本http://mirrors.jenkins-ci.or…

LINUX基础培训六之磁盘和文件系统管理

前言、本章学习目标 掌握fdisk分区类型和管理分区了解parted分区类型掌握LVM模式文件系统创建、扩展、缩小文件系统 一、磁盘的分区管理 在 Linux 中有专门的分区命令 fdisk 和 parted。其中 fdisk 命令较为常用&#xff0c;但不支持大于 2TB 的分区&#xff1b;如果需要支…

C++/WinRT 入门

本主题将会根据新的 Windows 控制台应用程序 (C/WinRT) 项目演练一个简单的代码示例。 C/WinRT 快速入门 创建一个新的 Windows 控制台应用程序(C/WinRT) 项目。 根据实际选择平台 如果出现如下错误&#xff0c;需要安装正确的SDK。 找不到 Windows SDK 版本 10.0.17134.0 (o…

支付功能测试用例测试点?

支付功能测试用例测试点是指在测试支付功能时&#xff0c;需要关注和验证的各个方面。根据不同的支付场景和需求&#xff0c;支付功能测试用例测试点可能有所不同&#xff0c;但一般可以分为以下几类&#xff1a; 功能测试&#xff1a;主要检查支付功能是否符合设计和业务需求…