上章回顾

常见的数据结构的形式

算法的时间复杂度是如何计算的

算法的空间复杂度是什么

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 pp

(插入前) (插入后)

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

qq

first ^ first p^p

qq

^

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/*mpbedclub.com,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