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

数据结构——单向链表

一、数据结构:

①常用的数据存储结构

②算法

③面向对象的编程思想

什么是数据结构?

①、用来组织和存储数据

②程序 = 数据结构 + 算法

二、数据与数据之间的关系

①逻辑结构:数据元素与元素之间的关系

集合:数据元素与数据元素之间平等的集合关系

线性结构:数据元素与元素之间存在一对一的关系(如:顺序表,链表,队列、栈)

树形结构:数据元素与元素之间存在一对多的关系(如:二叉树)

图形结构:数据元素与元素之间存在多对多的关系(如:网状结构)

②物理结构:数据元素在计算机内存中的存储方式

顺序结构:在内存中选用一段连续的内存空间进行存储

Ⅰ数据访问方便(O(1))

Ⅱ插入和删除数据是需要移动大量数据

Ⅲ需要预内存分配

Ⅳ可能造成大量的内存碎片

struct data
{char a;int b;
};

(原来只需char(一个字节)+ int(四个字节) 即五个字节,但在结构体中则需要八个字节进行存储)

链式结构:可以在内存中选用一段非连续的内存空间进行存储

Ⅰ数据访问时必须要从头遍历

Ⅱ插入和删除数据方便

Ⅲ不需要预内存分配,是一种动态存储方式

索引结构:将要存储的数据的关键字和存储位置之间构建构建一个索引表

散列结构(哈希结构):将数据的存储位置与数据元素之间的关键字建立起对应的关系(哈希函数),根据该关系进行数据的存储和查找

二、单向链表

由数据域和指针域组成结点

链表:对象(存储数据的对象) ——> 属性(变量)、行为(函数)

创建的链表指针指向 phead

接下里将从创建链表对象,插入数据,删除数据,查找数据,修改数据,销毁数据介绍单向链表

①创建链表对象

先建立三个文件分别是 (link .c(用于封装函数),link.h(用于存放函数声明),main.c(创建链表,调用函数进行编译))

在头文件中声明链表:

//链表存储的数据的数据类型
typedef int Date_type_t;//链表节点类型
typedef struct node
{Date_type_t date;struct node *pnext;
}Node_t;//链表的对象类型
typedef struct link
{Node_t *phead;int clen;
}Link_t;
Link_t *create_link()
{Link_t *plink = malloc(sizeof(Link_t));{if(NULL == plink){printf("error!\n");return NULL;}}plink -> phead = NULL;plink -> clen = 0;return plink;
}
#include <stdio.h>
#include "link.h"int main(int argc,const char *arvg[])
{Link_t *plink = create_link();if(NULL == plink){return -1;}
}

②插入数据(需要从堆上开辟空间,即动态分配内存,调用malloc函数)

Ⅰ头插

int insert_link_head(Link_t *plink,Date_type_t date)
{Node_t *pnode = malloc(sizeof(Node_t));if(NULL == plink ){printf("error!\n");return -1;}pnode -> date = date;  pnode -> pnext = NULL;   //数据初始化pnode -> pnext = plink ->phead;plink -> phead = pnode;plink -> clen++;return 0;
}//头插

(先使结构体指针指向节点,在于链表产生联系)

Ⅱ 尾插

int insert_link_tail(Link_t *plink,Date_type_t data)
{if(plink -> phead == NULL){return -1;}Node_t *ptmp = NULL;Node_t *pnode = malloc(sizeof(Node_t));if(pnode == NULL){return -2;}pnode -> date = data;pnode -> pnext = NULL;if(plink -> phead == NULL)//链表为空尾插即头插{plink -> phead = pnode; }else {ptmp = plink -> phead; while(ptmp -> pnext != NULL)//利用循环找到最后一个节点{ptmp = ptmp -> pnext;}}ptmp -> pnext = pnode;//找到最后一个节点插入数据plink -> clen ++;//扩展链表长度return 0;
}//尾插

③遍历链表

void link_for_each(Link_t *plink)
{Node_t *ptmp;ptmp = plink -> phead;while(ptmp != NULL){printf("%d\n",ptmp -> date);ptmp = ptmp -> pnext;}
}

③ 删除

Ⅰ头删

int delate_link_head(Link_t *plink)
{Node_t *ptmp = NULL; ptmp = plink-> phead;if(plink -> phead == NULL){return 0;}plink -> phead = ptmp -> pnext;free(ptmp);ptmp = NULL;plink -> clen--;return 1;
}

Ⅱ尾删

int delate_link_tail(Link_t *plink)
{Node_t *ptmp = NULL;ptmp = plink -> phead;if(ptmp == NULL){return -1;}if(ptmp -> pnext == NULL) //只有一个节点头删{free(ptmp);plink -> phead = NULL;plink -> clen = 0;return 1;}while(ptmp -> pnext -> pnext != NULL)//找倒数第二个节点{ptmp = ptmp -> pnext;}free(ptmp -> pnext);ptmp -> pnext = NULL;plink -> clen--;return 0;
}//尾删

④查找

Node_t *find_link(Link_t *plink,Data_type_t mydata)
{Node_t *ptmp;ptmp = plink -> phead;while(ptmp != NULL){Data_type_t s;s = ptmp -> date;if(s == mydata){break;}ptmp = ptmp -> pnext;}if(ptmp != NULL){return ptmp;}return NULL; 
}

⑤修改

int change_link(Link_t *plink,Date_type_t olddata,Date_type_t newdata)
{Node_t *p = NULL;p = find_link(plink,olddata);if(p == NULL){return -1;}p -> date = newdata;return 0;
}

⑥销毁

void destroy_link_head(Link_t *plink){if(plink -> phead == NULL){return;}Node_t *ptmp = NULL;Node_t *pnode = NULL;ptmp = plink -> phead;while(ptmp != NULL){pnode = ptmp -> pnext;free(ptmp);ptmp = pnode;}free(plink);
}//销毁链表

三、单向链表基础进阶

①查找中间值


int find_link_middle(Link_t *plink)//计数遍历找中间值
{Node_t *ptmp = NULL;int counter =  0;if(plink -> phead == NULL){return -1;}ptmp = plink -> phead;while(ptmp != NULL){++counter;ptmp = ptmp -> pnext;}ptmp = plink -> phead;for(int i = 0;i < counter / 2; ++i){ptmp = ptmp -> pnext;}return ptmp -> date;
}
Node_t *find_link_middle2(Link_t *plink) //快慢指针法
{if(plink -> phead == NULL){return NULL;}Node_t *pfast = plink -> phead;Node_t *pslow = plink -> phead;while(pfast != NULL){pfast = pfast -> pnext;if(pfast == NULL){break;}pfast = pfast -> pnext;pslow = pslow -> pnext;}return pslow;
}

②查倒数第k个节点

Node_t *find_link_random(Link_t *plink,int k)
{if(plink -> phead == NULL){return NULL;}Node_t *pfast = plink -> phead;for(int i = 0; i < k; ++i){pfast = pfast -> pnext;if(pfast == NULL){break;}}Node_t  *pslow = plink -> phead;while(pfast){pfast = pfast -> pnext;pslow = pslow -> pnext;}return pslow;
}

③链表逆序

void reverse_link(Link_t *plink)
{if(plink -> phead == NULL){return ;}Node_t *ptmp = plink -> phead;Node_t *pinsert = NULL;plink -> phead = NULL;while(ptmp){pinsert = ptmp;ptmp = ptmp -> pnext;pinsert -> pnext = plink -> phead ;plink -> phead = pinsert;}
}

⑤链表排序

void sort_link(Link_t *plink)
{if(plink -> phead == NULL){return ;}Node_t *ptmp = plink -> phead -> pnext;plink -> phead -> pnext = NULL;Node_t *pinsert = NULL;while(ptmp != NULL){pinsert = ptmp;ptmp = ptmp -> pnext;if(plink -> phead -> date >= pinsert -> date){pinsert -> pnext = plink -> phead;plink -> phead = pinsert;}else{Node_t *p = plink -> phead;while(p -> pnext != NULL && pinsert -> date > p -> pnext -> date){p = p -> pnext;}pinsert -> pnext = p -> pnext;p -> pnext = pinsert;}}}

⑥判断链表是否有环

Node_t *link_hascycle(Link_t *plink)
{if(plink -> phead == NULL){return NULL;}Node_t *pfast = plink -> phead;Node_t *pslow = plink -> phead;while(pfast != NULL && pfast -> pnext != NULL){pfast = pfast -> pnext -> pnext;pslow = pslow -> pnext;if(pslow == pfast){return pslow;}}return NULL;
}

⑦约瑟夫环问题

Node_t *is_link_joseph(Link_t *plink,int n)
{if(plink -> phead == NULL){return NULL;    }if(plink -> clen ==1){return plink -> phead;}Node_t *pnode = NULL;pnode = plink -> phead;Node_t *p = NULL;p = plink -> phead;while(p -> pnext != NULL){p = p -> pnext;}p -> pnext = plink -> phead;Node_t *ptmp = NULL;ptmp = p;while(plink -> clen > 1){int i;for(i = 0; i < n - 1; ++i){ptmp = pnode;pnode = pnode -> pnext;}ptmp -> pnext = pnode -> pnext;if(pnode == plink -> phead){plink -> phead = pnode -> pnext;}Node_t *q = pnode;pnode = pnode -> pnext;free(q);plink -> clen--;}pnode = pnode -> pnext;return pnode; 
}

http://www.lryc.cn/news/609771.html

相关文章:

  • CMakeLists.txt学习
  • 《JavaScript高级程序设计》读书笔记 35 - 代理捕获器、反射方法以及代理模式
  • React 19 + Next.js 15 中实现混合布局
  • React配置proxy跨域
  • ref和reactive的区别
  • 通过 Flink 和 CDC 从 Oracle 数据库获取增量数据,并将这些增量数据同步到 MySQL 数据库中
  • [GESP202306 四级] 2023年6月GESP C++四级上机题超详细题解,附带讲解视频!
  • Spring Boot + ShardingSphere 实现分库分表 + 读写分离实战
  • AWS VPC Transit Gateway 可观测最佳实践
  • 【物联网】基于树莓派的物联网开发【23】——树莓派安装SQLite嵌入式数据库
  • 16_OpenCV_漫水填充(floodFill)
  • Nginx vs Spring Cloud Gateway:限流功能深度对比与实践指南
  • Spring Cloud Gateway 实现登录校验:构建统一认证入口
  • 图片的放大缩小选择全屏
  • XSS的原型链污染1--原型链解释
  • 笔记本电脑联想T14重启后无法识别外置红米屏幕
  • Django + Vue 项目部署(1panel + openresty)
  • AI“炼金术”:破解绿色水泥的配方密码
  • 三防平板电脑是什么?这款三防平板支持红外测温!
  • 电脑上不了网怎么办?【图文详解】wifi有网络但是电脑连不上网?网络设置
  • 电脑一键重装系统win7/win10/win11无需U盘(无任何捆绑软件图文教程)
  • Ribbon 核心原理与架构详解:服务负载均衡的隐形支柱
  • 工作流绑定卡片优化用户体验-练习我要找工作智能体
  • 【CVPR2025】计算机视觉|AnomalyNCD:让工业异常分类“脱胎换骨”!
  • transformer与神经网络
  • ubuntu24.01安装odoo18
  • 纯前端使用ExcelJS插件导出Excel
  • 计算机视觉(2)车规摄像头标准
  • 5天挑战网络编程 -DAY1(linux版)
  • python:讲懂决策树,为理解随机森林算法做准备,以示例带学习,通俗易懂,容易理解和掌握