C 项目案例实践(1)数据结构之链表(0)
链表是通过一组任意的存储单元来存储线性表中的数据元素的,那么怎样表示出数据元素之间的线性关系呢?为建立数据元素之间的线性关系,对每个数据元素ai,除了存放数据元素的自身信息ai之外,还需要存放和ai一起存放其后继ai+1所在的存储单元的地址,这两部分信息组成一个"节点"(如图),存放数据元素信息的称为数据域,存放其后继地址的称为指针域。因此,n个元素的线性表通过每个节点的指针域拉成了一条"链子", 称之为链表。因为每个节点中只有一个指向后继的指针,所以称之为单链表。
链表是由一个个节点构成,节点定义如下:
typedef struct node
{
datatype data;
struct node *next;
}LNode, *LinkList;
定义指针变量: LinkList H;
下图分别是带头节点的单链表空表和非空表的示意图
注:LNode是节点的类型,LinkList是指向LNode类型节点的指针类型。
在操作中需要用到某节点的指针变量时, 做如下声明是等价的。
LNode *p; 等价于 LinkList H;
p = malloc(sizeof(LNode)); 表示申请一块LNode类型的存储单元,并将这块存储空间的地址赋值给变量p. p所指的节点为*p, *p的类型为LNode型,所以该节点的数据域为(*p).data 或 p->data, 指针域为(*p)->next, 或 p->next。
存储空间的分配和释放
1.存储空间分配函数原型: void *malloc(unsigned int size);
作用是在内存中动态获取一个大小为size个字节的连续的存储空间。并返回一个void类型的指针,若分配成功,该指针指向已分配空间的起始地址,否则,该指针将为空(NULL)
2.连续空间分配函数原型: void *calloc(unsigned, n unsigned size);
作用是在内存中动态获取n个大小为size个字节的连续的存储空间。 该函数将返回一个void类型指针,若分配成功,该指针指向已分配空间的首地址,否则返回空(NULL)。用calloc()可以动态获取一个一维数组空间,其中n为数组元素个数,每个数组元素的大小为size个字节。
3.空间释放函数原型:void free(void *addr);
free()的作用是释放由addr指针所指向的空间,即系统回收,使这段空间又可以被其它变量所用。
建立和输出链表
所谓动态建立链表是指在程序执行过程中从无到有地建立链表,将一个个新生成的节点依次链接入已建立起来的链表上。上一个节点的指针域存放下一个节点的起始地址,并给各个节点数据域赋值。
例如,建立一个学生成绩的链表,其节点的结构体定义如下:
struct student
{
long num;
char name[20];
float score;
struct student *next;
};
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
4步建立链表:
1.定义三个指针变量,head头指针,p1指向新节点,p2指向尾节点
2.产生一个节点, head , p1和p2都指向它,并输入想要的数据。
3.循环操作,陆续产生新节点,输入数据,链接到表尾
4.最后,尾节点指针域置空,返回头指针。
create()函数创建链表, 返回链表头指针:
struct student *create()
{
struct student *p1, *p2, *head;
int i, n = 2;
head = NULL;
head = p1 = p2 = (struct student *) malloc(sizeof(struct student));
if(!head) return false; //检测内存空间是否申请成功
printf("input num name score\n");
scanf("%ld%s%f",&p1->num,&p1->name,&p1->score);
for(int i = 1; i<n; i++)
{
p1= (struct student *)malloc(sizeof(struct student));
if(!p1) return false;
scanf("%ld%s%f",&p1->num,&p1->name,&p1->score);
p2->next = p1;
p2 = p1;
}
p2->next = NULL;
return head;
}
利用print()函数输出链表数据:
void print(struct student *p)
{
while(p != NULL)
{
printf("ID: %ld Name: %10s score:%6.2f\n",p->num,p->name,p->score);
p=p->next;
}
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }最后在main函数中完成调用工作:
int main(void)
{
struct student *head;
head = create();
print(head);
fflush(stdin);
getchar();
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }单链表的基本操作
1.插入。
如果要在单链表的两个数据元素之间插入一个数据元素x,已知p为其单链表存储结构中指向节点a的指针(如图(a)),为插入数据元素x,首选要生成一个数据域为x的节点,然后插在单链表中,插入前需要修改节点a中的指针域,令其指向节点x,而节点x中的指针域应指向节点b,从而实现三个元素a,b和x之间逻辑关系的变化。插入单链表如图(b),假设s为指向节点x的指针,则上述过程可表述如下:
s->next = p->next;
p->next = s;
图(a)
图(b)
2.删除
要删除单链表中的元素x,仅需要把x节点的指针域目前保存的它的下一个节点b的地址赋值给a节点的指针域即可。 假设p,q分别是指向a,x节点的指针,则:
p->next = q->next;
free(q);
3.查找
链表查找是指在链表中查找某成员值为给定值的节点。下面定义一个查找函数,它的返回值即为指向查找到的节点的指针。查找方法是先输入要查找的给定值,然后从链表的头指针所指的第一个节点开始,按链接顺序逐一比较:当查找到给定值的节点时,则返回该节点,否则返回空指针。
struct student *find(struct student *p)
{
long num;
printf("Input the std ID :");
scanf("%ld",&num);
while(p != NULL)
{
if(num == p->num) return p;
p = p->next;
}
return NULL;
}
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
双链表
单链表的节点中只有一个指向其后继节点的指针域next, 因此,若已知某节点的指针为p, 其后继节点的指针则为p->next, 而找其前驱则只能从该链表的头指针开始,顺着各节点的next域进行,也就是说找后继的时间性能是O(1),而找前驱的时间性能是O(n) , 如果希望找前驱的时间性能达到O(1),则只能付出空间代价:每个节点再加一个指向前驱的指针域,节点的结构如图(1),用这种节点组成的链表称为双向链表:
双链表节点的定义如下:
typedef struct dlnode
{
datatype data;
struct dlnode *prior , *next;
}DLNode , *DLinkList;
与单链表类似,双向链表通常也是用头指针标识,也可以带头节点和作成循环结构,图2是带头节点的双向链表图。显然通过某节点的指针p即可以直接得到它的后继节点指针p->next和前驱节点p->prior. 假设p是指向双向循环链表中的某一节点的指针,则p->prior->next表示的是*p节点的前驱节点的后继节点的指针,即与p相等。
.csharpcode, .csharpcode pre
{
font-size: small;
color: black;
font-family: consolas, "Courier New", courier, monospace;
background-color: #ffffff;
/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt
{
background-color: #f4f4f4;
width: 100%;
margin: 0em;
}
.csharpcode .lnum { color: #606060; }
C 项目案例实践(1)数据结构之链表(0)的更多相关文章
- Selenium自动化测试项目案例实践公开课
Selenium自动化测试项目案例实践公开课: http://gdtesting.cn/news.php?id=55
- C项目案例实践(0)-语言基础
1.C语言数据类型 所谓数据类型是按被定义变量的性质.表示形式.占据存储空间的多少.构造特点来划分的.C中数据类型可分为基本数据类型.构造数据类型.指针类型.空类型4大类,结构如图: (1)基本数据类 ...
- Hadoop学习笔记—20.网站日志分析项目案例(一)项目介绍
网站日志分析项目案例(一)项目介绍:当前页面 网站日志分析项目案例(二)数据清洗:http://www.cnblogs.com/edisonchou/p/4458219.html 网站日志分析项目案例 ...
- TOP100summit 2017:小米唐沐等大咖精心挑选的100个年度研发案例实践
2017年,机器学习.大数据.人工智能等词汇成为软件研发行业的主流,大前端.DevOps.区块链等技术方式成为热点方向:2017年,智能硬件开始成为新的焦点,这一年更被称为智能音箱井喷的一年:2017 ...
- ASP.NET Core基于K8S的微服务电商案例实践--学习笔记
摘要 一个完整的电商项目微服务的实践过程,从选型.业务设计.架构设计到开发过程管理.以及上线运维的完整过程总结与剖析. 讲师介绍 产品需求介绍 纯线上商城 线上线下一体化 跨行业 跨商业模式 从0开始 ...
- 前端 go.js 流程图基于vue开发项目案例
一.流程图效果 最近一段时间在研究go.js,它是一款前端开发画流程图的一个插件,也是一个难点,要说为什么是难点,首先,它是依赖画布canvas知识开发.其次,要依赖于内部API开发需求,开发项目需求 ...
- 测试开发实战[提测平台]20-图表G2Plot在项目的实践实录
微信搜索[大奇测试开],关注这个坚持分享测试开发干货的家伙. G2Plot项目应用 上一篇<提测平台19-Echarts图表在项目的实践>讲解了Echarts的图表应用,此篇来看下开箱即用 ...
- Kafka与Spark案例实践
1.概述 Kafka系统的灵活多变,让它拥有丰富的拓展性,可以与第三方套件很方便的对接.例如,实时计算引擎Spark.接下来通过一个完整案例,运用Kafka和Spark来合理完成. 2.内容 2.1 ...
- 学习javascript数据结构(二)——链表
前言 人生总是直向前行走,从不留下什么. 原文地址:学习javascript数据结构(二)--链表 博主博客地址:Damonare的个人博客 正文 链表简介 上一篇博客-学习javascript数据结 ...
随机推荐
- windows下安装rabbitmq以及php扩展amqp
先安装RabbitMQ 安装Erlang 下载地址http://www.erlang.org/downloads 我选的是64位 这个根据自己情况下载,双击安装之 安装RabbitMQ 下载地址ht ...
- LeetCode 309. Best Time to Buy and Sell Stock with Cooldown (stock problem)
Say you have an array for which the ith element is the price of a given stock on day i. Design an al ...
- STM32F407 外部中断 个人笔记
IO口 STM32F4有上百个IO口中,每个都可以作为外部中断输入 中断线 STM32F4的中断控制器支持22个外部中断/事件请求(中断线) 对于每个中断线,我们可以设置相应的触发方式(上升沿触发,下 ...
- Leetcode 306.累加数
累加数 累加数是一个字符串,组成它的数字可以形成累加序列. 一个有效的累加序列必须至少包含 3 个数.除了最开始的两个数以外,字符串中的其他数都等于它之前两个数相加的和. 给定一个只包含数字 '0'- ...
- 70.打印所有Spring boot载入的bean【从零开始学Spring Boot】
[从零开始学习Spirng Boot-常见异常汇总] 问题的提出: 我们在开发过程当中,我们可能会碰到这样的问题:No qualifying bean 就是我们定义的bean无法进行注入,那到底是什 ...
- (3)梯度下降法Gradient Descent
梯度下降法 不是一个机器学习算法 是一种基于搜索的最优化方法 作用:最小化一个损失函数 梯度上升法:最大化一个效用函数 举个栗子 直线方程:导数代表斜率 曲线方程:导数代表切线斜率 导数可以代表方向, ...
- devstack脚本安装Openstack总结(转载)
1:vmware 基本设置 我采用的vmware workstation 8.0的版本,其他版本应该都是没问题.我是把虚拟机放在NAT的网络. 虚拟机就单块网卡就可以. 如果你希望可以在dashboa ...
- 【dp】codeforces C. Vladik and Memorable Trip
http://codeforces.com/contest/811/problem/C [题意] 给定一个自然数序列,在这个序列中找出几个不相交段,使得每个段的异或值之和相加最大. 段的异或值这样定义 ...
- hdu 2167 状态压缩
/*与1565的解法差不多*/ #include<stdio.h> #include<string.h> int map[16][16]; int dp[2][1<< ...
- CPU问题定位与解决
CPU问题定位基本流程: 性能计数器诊断 主要用到的性能计数器 %Process Time 全实例 (主要用于查看当前服务器的CPU 情况) %Process Time sqlservr (主要用 ...