上章回顾
常见的数据结构的形式
算法的时间复杂度是如何计算的
算法的空间复杂度是什么
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
第四章
第四章
链表
链表
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
预习检查
什么是线性链表
什么是循环链表
什么是双向链表
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
课程目标
本章概述
重点
难点
本章主要介绍运用结构体构造链表,以及链表的相应的操作
本章目标
熟练构造和掌握链表及相关添加,查找,删除操作。
掌握链表的构造以及相关操作。
链表的各种操作
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
本章结构
数据结构与算法初步
数据结构与算法初步
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
单向链表操作
单向链表操作
双向循环链表
双向循环链表
4.1链表
单链表
单链表上基本运算的实现
循环链表
双向链表
静态链表
单链表的应用实例
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
4.1.1 单链表 单链表的概述
动态进行存储分配的一种结构
在内存中不连续存放
头节点:指向第一个元素
节点:链表中的每一个元素(结构体) 两部分:实际数据和下一个节点地址
尾指针
定义
typedef struct node
{ datatype data;
struct node *next; } LNode,*LinkList;
/* 指向本结点类型的指针是实现链表的基础 */
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
4.1.1 单链表 单链表的概述
定义
动态进行存储分配的一种结构
在内存中不连续存放
头节点:指向第一个元素
节点:链表中的每一个元素(结构体) 两部分:实际数据和下一个节点地址
尾指针
typedef struct node
{
datatype data;
struct node *next; } LNode,*LinkList;
/* 指向本结点类型的指针是实现链表的基础 */
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
4.1.1 单链表 头指针来标识一个单链表,如单链表L、单链表H等,是
指某链表的第一个结点的地址放在了指针变量 L、H 中,
头指针为“NULL”则表示一个空表
内存分配函数:
void * malloc(unsigned int size)
void * calloc(unsigned n,unsigned size)
分配成功返回指向起始地址的指针 分配不成功返回NULL
内存释放函数
void free(void *p)
申请链表空间
p=malloc(sizeof(LNode));
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
4.1.1 单链表
带表头结点的单链表
表头结点位于表的最前端,本身不带数据,仅标志表头
设置表头结点的目的: 简化链表操作的实现
first a1 an ^ first ^ ^^
非空表
空表
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
4.1.2.单链表上基本运算的实现 建立单链表
求表长
查找操作 插入 删除
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
4.1.2.1建立单链表
在链表的头部插入结点建立单链表
first
newnode->next = first ; first = newnode;
newnode newnode
(插入前)
(插入后)
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
first
4.1.2.1建立单链表 在链表的头部插入结点建立单链表
算法如下:
LinkList Creat_LinkList1( ) {
LinkList L=NULL;/*空表*/
Lnode *s;
int x; /*设数据元素的类型为int*/ scanf("%d",&x);
while (x!=flag)
{
s=malloc(sizeof(LNode)); s->data=x;
s->next=L; L=s;
scanf ("%d",&x);
}
return L;
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
}
4.1.2.1建立单链表 在单链表的尾部插入结点建立单链表
newnode->next = p->next; p->next = newnode;
newnode newnode p∧p
∧
(插入前) (插入后)
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
4.1.2.1建立单链表
在链表的尾部插入结点建立单链表
算法如下:
LinkList Creat_LinkList2( ) {
LinkList L=NULL;
Lnode *s,*r=NULL;// r为哨兵指针
int x; /*设数据元素的类型为int*/ scanf("%d",&x);
while (x != flag) {
s=malloc(sizeof(LNode));
s->data=x;
if (L==NULL) L=s; /*第一个结点的处理*/ else r->next=s; /*其它结点的处理*/ r=s; /*r 指向新的尾结点*/ scanf("%d",&x);
}
if ( r!=NULL) r->next=NULL; /*对于非空表,最后结点的
嵌入式家园 www.embedclub.com指针域放空指针*/
return L;
上海嵌入式家园-开发板商城 http://embedclub.taobao.com/}
4.1.2.1建立单链表
在链表中间插入 newnode->next = p->next;
p->next = newnode ; newnode newnode
p
p
(插入后) 上海嵌入式家园-开发板商城 http://embedclub.taobao.com/
(插入前)
嵌入式家园 www.embedclub.com
4.1.2.2 求表长 带头节点的链表
算法思路:设一个移动指针p和计数器j,初始化后,p所指结点后面 若还有结点,p向后移动,计数器加1。
算法如下:
int Length_LinkList1 (LinkList L) {
}
Lnode * p=L; /* p指向头结点*/ int j=0;
while (p->next) {
return j;
p=p->next;
j++
} /* p所指的是第 j 个结点*/
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
4.1.2.2 求表长 不带头节点的链表
算法思路:设一个移动指针p和计数器j,初始化后,p所指结点后 面若还有结点,p向后移动,计数器加1。
算法如下:
int Length_LinkList2 (LinkList L) {
Lnode * p=L;
int j;
if (p==NULL) return 0; /*空表的情况*/
j = 1; /*在非空表的情况下,p所指的是第一个结点*/; while (p->next )
{
}
return j;
p=p->next; j++
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
}
4.1.2.2 查找操作 按序号查找
算法思路:从链表的第一个元素结点起,判断当前结点是否是第i个,若 是,则返回该结点的指针,否则继续后一个,表结束为止。没有第i个
结点时返回空 。 算法如下:
Lnode * Get_LinkList(LinkList L, Int i); /*在单链表L中查找第i个元素结点,找到返回其指针,否则返回空*/
{
Lnode * p=L;
int j=0;
while (p->next !=NULL && j<i ) {
}
if (j==i)
p=p->next; j++;
return p;
else
return NULL;
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
}
4.1.2.2 查找操作 按值查找即定位
算法思路:从链表的第一个元素结点起,判断当前结点其值是否等于x, 若是,返回该结点的指针,否则继续后一个,表结束为止。找不到时返
回空 。 算法如下:
Lnode * Locate_LinkList( LinkList L, datatype x) /*在单链表L中查找值为x的结点,找到后返回其指针,否则返回空*/ {
}
Lnode * p=L->next;
while ( p!=NULL && p->data != x)
p=p->next; return p;
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
4.1.2.3 插入 后插结点
插入前
插入后
first
first
q->next = p->next; p->next = q;
pp
first ^ first p^p
^
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
^
4.1.2.3 插入 插入运算
算法如下:
int Insert_LinkList( LinkList L, int i, datatype x) /*在单链表L的第i个位置上插入值为x的元素*/
{
Lnode * p,*s;
p=Get_LinkList(L,i-1); /*查找第i-1个结点*/ if (p==NULL)
{
printf("参数i错");return 0; } /*第i-1个不存在不能插入*/
else {
}
嵌入式家园 www.embedclub.com
s=malloc(sizeof(LNode)); /*申请、填装结点*/
s->data=x;
s->next=p->next; /*新结点插入在第i-1个结点的后面*/
p->next=s
return 1;
上海嵌入式家园-开发板商城 http://embedclub.taobao.com/}
4.1.2.4 删除
在单链表中删除ai结点 q = p->next;
p->next = q->next;
删除前 Ai-1 Ai-1
ai Ai+1
p
删除后 ai-1 pq
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
ai Ai+1
ai ai+1
...
4.1.2.4 删除 在单链表中删除ai结点:
算法如下
int Del_LinkList(LinkList L,int i) {
/*删除单链表L上的第i个数据结点*/
LinkList p,s;
p=Get_LinkList(L,i-1); /*查找第i-1个结点*/ if (p==NULL) {
return -1; } else {
printf("第i-1个结点不存在");
if (p->next==NULL) { printf("第i个结点不存在");
return 0; } else {
s=p->next; /*s指向第i个结点*/
p->next=s->next; /*从链表中删除*/
free(s); /*释放*s */ 嵌入式家园 www.embedclub.com
}
}
上海嵌入式家园-开发板商城 http://embedclub.taobao.com/return 1;
4.1.3 循环链表
特点:
可以从表中任意结点开始遍历整个链表 不用头指针而用一个指向尾结点的指针R来标识
带头节点的单循环链表
H
a1
... an H
(b)空表
(a)非空表
图2.16 带头结点的单循环链表
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
4.1.3 循环链表
单循环链表H1 、H2的连接操作 链表若用尾指针R1 、R2来标识 将H2的第一个数据结点接到H1的尾结点
操作语法
p
R1
R2
p= R1 –>next; /*保存R1 的头结点指针*/ R1->next=R2->next->next; /*头尾连接*/ free(R2->next); /*释放第二个表的头结点*/
R2->next=p; /*组成循环链表*/
a1 ... an ×
b1 ... bn ×
两个用尾指针标识的单循环链表的连接
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
4.1.4 双向链表
特点
一个指向前驱的指针域
一个指向后驱的指针域
一个数据域
prior data next
定义表达:
typedef struct dlnode
{
datatype data;
struct dlnode *prior,*next;
}DLNode,*DLinkList;
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
双向链表
4.1.4 双向链表 链表表现模式
H
H
...
a1 a2 an
图2.19 带头结点的双循环链表
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
(b)空表
(a)非空表
4.1.5 单链表应用举例 例一
H
∧ (a) 25 45 18 76 29∧ (b)
H
已知单链表H,写一算法将其倒置。即实现如图2.22的操作。(a)为倒置前, (b)为倒置后。
29 76 18 45 25
单链表的倒置
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
4.1.6 单链表应用举例 例一
算法表达:
void reverse (Linklist H) {
} }
LNode *p;
p=H->next; /*p指向第一个数据结点*/ H->next=NULL; /*将原链表置为空表H*/ while (p)
{
q=p;
p=p->next;
q->next=H->next; /*将当前结点插到头结点的后面*/ H->next=q;
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
4.1.6 单链表应用举例 例二
H
10 15 18 15 10
∧
已知单链表L,写一算法,删除其重复结点,即实现如图2.23的操作。(a)为 删除前,(b)为删除后
(a) H 101518∧(b)
删除重复结点
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
4.1.6 单链表应用举例 例二
算法实现
void pur_LinkList(LinkList H) { LNode *p,*q,*r;
p=H->next; /*p指向第一个结点*/ if(p==NULL) return;
while (p->next)
{ q=p;
while (q->next)
/* 从*p的后继开始找重复结点*/ if (q->next->data==p->data)
{
*r */
{
r=q->next; /*找到重复结点,用r指向,删除
q=q->next; } /*while(q->next)*/
嵌入式p家=p-园>newxtw; w.e/*mp指be向dc下lu一b.c个om,m继续*/ } /*while(p->next)*/
上海嵌入式家园-开发板商城 http://embedclub.taobao.com/}
} /*if*/ else
q->next=r->next; free(r);
阶段小节
单链表的特点
单链表的创建,插入、查找和删除 循环链表与双向链表特点
实现链表的逆转
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
本章总结
数据结构与算法初步
数据结构与算法初步
主要讲述循环链表的基 作
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git
单向链表操作
单向链表操作
主要讲述单链表的基本
作,包括插入、删除以
找
双向循环链表
双向循环链表
实验1 题目
通过键盘输入7个数字,并建立链表,并用typedef定义链表结构指针,同时实现对 链表数据进行从大到小的排序,输入排序的最终解构,最后删除链表最大值。排序 算法可以采用冒泡排序
实验目的
回顾typedef定义细节 熟悉掌握链表的基本操作 熟悉运用基本的排序算法
实验分析
定义一个链表节点指针
键盘输入数据并建表
数据排序并输入排序的最终结果
删除尾节点
git@github.com:Kevin-Dfg/Data-Structures-and-Algorithm-Analysis-in-C.git