当前位置: 首页 > news >正文

数据结构学习之链表学习:单链表

        在之前顺序表的学习过程中,我们知道顺序表中头插和中插的复杂度是O(N)。那我们可不可以将其降低为O(1)呢?可不可以不增容想用就用想扔就扔而不会浪费一点空间呢?那就是我们今天的内容:链表

        继我们学习了顺序表之后,接下来我们就来学习顺序表的下一个内容:链表。

目录

链表

单链表

        单链表的组成

       创建单链表的新节点

        单链表的尾插

        单链表的头插

       单链表的尾删

        单链表的头删

        单链表的查找

        单链表插入数据

        指定位置之前

        指定位置之后

单链表删除数据 

        指定结点

        指定节点之后

         单链表的结点数据修改

        单链表的销毁


链表

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

        那么链表是如何实现的呢?

        以火车为例,火车的车头和车厢并不是粘连在一起的,而是通过连接起来的,可以增减车厢的个数。每个车厢是独立存在的,增减某一元素对原有数据不影响

        再单链表中“车厢”就是结点,而单链表就是由结点构成的。

        而由于上图可知,结点是由数据元素及保存下一个结点地址的指针组成的。

        接下来我们来学习单链表的实现。

单链表

        我们需要三个文件来准备

SList.h——声明结构体的组成、声明函数方法

SList.c——实现函数

test.c——单链表测试

        单链表的组成

typedef int SListDataType;
//定义链表结构——节点
typedef struct SListNode
{SListDataType data;//保存的数据struct SListNode* next;//指向下一个节点的指针
}SLN;

        单链表的打印函数

SList.h

//链表的打印
void SLN_print(SLN* next);

SList.c

//链表的打印
void SLN_print(SLN* phead)
{SLN* p = phead;while(p!= NULL)//可以简写为while(p){printf("%d ->", p->data);p = p->next;}printf("NULL\n");
}

       创建单链表的新节点

//根据x创建节点
SLN* SLN_buy_node(SListDataType x)
{//根据x创建结点SLN* new_node = (SLN*)malloc(sizeof(SLN));if (new_node == NULL){perror("malloc error");return  1;}new_node->data = x;new_node->next = NULL;return new_node;
}

        单链表的尾插

        前面我们知道链表是依赖于指针连接起来的,所以我们创建一个空链表是这样的

//创建一个空链表
SLN* slist =NULL;

        因此,我们进行尾插的时候分为两种情况:链表为空和链表不为空

        链表为空时,直接将新结点赋值给首结点;不为空时,从前往后走,当指针不为空时向后走,当指针为空的时候跳出循环,插入结点,尾部节点指针为NULL。

        代码为:

//链表的尾插
void SLN_back_push(SLN** pphead, SListDataType x)
{SLN* new_node = SLN_buy_node(x);//链表为空if (*pphead == NULL){*pphead = new_node;}else{//找尾结点SLN* ptail = *pphead;while (ptail->next){ptail = ptail->next;}//找到尾结点ptail->next = new_node;}
}

        单链表的头插

        头插思路:

        

//链表的头插
void SLN_head_push(SLN** pphead, SListDataType x)
{assert(pphead!=NULL);SLN* new_node = SLN_buy_node(x);new_node->next = *pphead;*pphead = new_node;
}

       单链表的尾删

//链表的尾删
void SLN_back_pop(SLN** pphead)
{assert(pphead!= NULL&&*pphead!= NULL);//找prev和ptailSLN*prev = NULL;SLN*ptail = *pphead;//找尾结点while (ptail->next != NULL){prev = ptail;ptail=ptail->next;}prev->next = NULL;free(ptail);ptail = NULL;
}

但是这段代码当链表只有一个结点的时候就会出错, 

        单链表的头删

void SLN_head_pop(SLN** pphead)
{assert(pphead != NULL && *pphead != NULL);SLN*next=(*pphead)->next;free(*pphead);*pphead=next;
}

        单链表的查找

//链表的查找
SLN* SLN_find(SLN* pphead, SListDataType x)
{SLN*p=pphead;while (p != NULL){if (p->data == x){printf("find %d\n", x);return p;}p = p->next;}return NULL;
}

        单链表插入数据

        指定位置之前

        思路图:

        prev的指针指向newcode的数值,newcode的next指针指向pos 

        代码:

//指定位置之前插入
void SLN_Before_insert(SLN** pphead, SLN* pos, SListDataType x) 
{assert(pphead != NULL && pos != NULL);// pos 是头节点,执行头插if (pos == *pphead) {SLN_head_push(pphead, x);}else {SLN* newnode = SLN_buy_node(x);// 找pos的前一个结点SLN * prev = *pphead;while (prev->next != pos){prev = prev->next;}	//prev--> newnode--> pos prev->next = newnode;prev->next = newnode;newnode->next = pos;}
}

        指定位置之后

思路图:

        

        只需要将pos的next指针指向newcode,将nextcode的next指针指向下一个数据,即以下这种情况:

newcode->next=pos->next;
pos->next=newcode;

代码:

//指定位置之后插入
void SLN_After_insert( SLN* pos, SListDataType x)
{assert(pos);SLN* newnode = SLN_buy_node(x);newnode->next = pos->next;pos->next = newnode;	
}

单链表删除数据 

        指定结点

        思路:

        

//指定结点删除
void SLN_delete(SLN** pphead, SLN* pos)
{assert(pphead&&pos);//pos是第一个节点if (pos==*pphead){SLN_head_pop(pphead);}else{SLN* prev = *pphead;while (prev->next != pos){prev = prev->next;}prev->next = pos->next;free(pos);pos = NULL;}	
}

        指定节点之后

//指定位置之后插入
void SLN_After_insert( SLN* pos, SListDataType x)
{assert(pos);SLN* newnode = SLN_buy_node(x);newnode->next = pos->next;pos->next = newnode;	
}

         单链表的结点数据修改

//链表的数据修改
void SLN_change(SLN** pphead, SLN* pos, SListDataType x)
{assert(pos);pos->data = x;
}

        单链表的销毁

//链表的销毁
void SLN_destroy(SLN** pphead)
{SLN* p = *pphead;while (p != NULL){SLN*next=p->next;free(p);p=next;}*pphead = NULL;
}

        本期单链表的内容到此结束,后续我们会就单链表的问题进行一些题目的练习,或者学习其他的链表结构。在这里求个赞,谢谢

相关文章:

  • Linux笔记---信号(中)
  • AIGC与数字媒体实验室解决方案分享
  • LabVIEW在电子电工教学中的应用
  • 腾讯云运营开发 golang一面
  • map和unordered_map
  • 树莓派3B+ wiringPi库安装
  • Gin 框架指南(代码+通俗解析版)
  • linux - 权限的概念
  • 嵌入式开发学习日志(数据结构--单链表)Day20
  • docker-compose——安装mysql8
  • 【springcloud学习(dalston.sr1)】Eureka 客户端服务注册(含源代码)(四)
  • GAN简读
  • 我的多条件查询
  • C2S-Scale:Cell2Sentence v2
  • 基于EFISH-SCB-RK3576/SAIL-RK3576的CNC机床控制器技术方案‌
  • Ubuntu磁盘空间分析:du命令及常用组合
  • [思维模式-37]:什么是事?什么是物?什么事物?如何通过数学的方法阐述事物?
  • 360智语:以全栈技术重塑企业级智能体开发新标杆
  • 【行为型之观察者模式】游戏开发实战——Unity事件驱动架构的核心实现策略
  • 基于 art 下的类加载机制,实现函数抽取壳
  • 河南省委常委会会议:坚持以案为鉴,深刻汲取教训
  • 专访|导演刘江:给谍战题材注入现实主义的魂
  • 小米SU7 Ultra风波升级:数百名车主要求退车,车主喊话雷军“保持真诚”
  • 牟海松任国家信访局副局长
  • 季子文化与江南文化的根脉探寻与融合
  • 国际博物馆日中国主会场确定,北京将展“看·见殷商”等展览