第15讲 链表 计算机与通信工程学院.

Slides:



Advertisements
Similar presentations
数据结构的引入. 通讯录管理 社团机构管理 校园导航管理 通讯录管理 社团机构管理 校园导航管理.
Advertisements

考场纪律&监考要求 课程主讲人和主持人要亲自参加监考。
第10章 结构体与链表 本章要点: 结构体类型与结构体变量的定义 结构体变量的引用与初始化 结构体数组 链表处理 共用体类型和枚举类型
第三章 鏈結串列 Linked List.
第二章 线性表 1 线性表的逻辑结构及其基本操作 2 线性表的顺序存储结构 3 线性表的链式存储结构 4 静态链表 5 应用实例.
第二章 线性表.
C++中的声音处理 在传统Turbo C环境中,如果想用C语言控制电脑发声,可以用Sound函数。在VC6.6环境中如果想控制电脑发声则采用Beep函数。原型为: Beep(频率,持续时间) , 单位毫秒 暂停程序执行使用Sleep函数 Sleep(持续时间), 单位毫秒 引用这两个函数时,必须包含头文件
第九章 系 统 安 全 性 9.1 结构体 9.2 结构体型数组  9.3 结构体型指针 9.4 内存的动态分配 9.5 共用体
第3章 栈和队列 3.1 栈 3.2 队列 3.3 应用.
單向鏈結串列 Singly Linked Lists.
第2章 线性表 线性结构 是一个数据元素的有序集合。.
其他类型的链表主要内容 静态链表 循环链表 双向链表.
第三章 栈和队列 Stack and Queue
第二章 线性表 线性表 顺序表 链表 顺序表与链表的比较.
第7章 结构体、联合体和枚举类型 本章导读 本章主要知识点 《 C语言程序设计》 (Visual C++ 6.0环境)
C程序设计 第9章 自定义数据类型 主讲教师: 鲁 萍 西安建筑科技大学 理学院.
親愛的老師您好 感謝您選用本書作為授課教材,博碩文化準備本書精選簡報檔,特別摘錄重點提供給您授課專用。 說明: 博碩文化:
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
第9章 结构体.
结构体和共用体 2 梁春燕 华电信息管理教研室.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
C++语言程序设计 C++语言程序设计 第四章 数组及自定义数据类型 C++语言程序设计.
第九章 结构体和共用体 结构体的定义 结构体的使用 共用体的定义 共用体的使用 主讲:李祥 时间:2015年10月.
教 师:曾晓东 电 话: E_mail: 计算机软件技术基础 教 师:曾晓东 电 话: E_mail:
C语言程序设计 李祥.
辅导课程六.
西安交通大学计教中心 ctec.xjtu.edu.cn
第2章 线性表 线性表抽象数据类型 顺序表 主要知识点 单链表 循环单链表 循环双向链表 静态链表 设计举例.
第 1 章 数据结构 1.1 基本数据结构与算法 1.2 线性表 1.3 栈和队列 1.4 树和二叉树 1.5 查找 1.6 内部排序 65
第十章 C高级程序应用—链表* 10.1链表的基本概念 10.2单向链表 10.3双向链表 10.4应用举例.
第5章 堆疊(Stacks) 5-1 堆疊的基礎 5-2 堆疊的表示法 5-3 堆疊的應用 - 運算式的計算與轉換
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
Zhao4zhong1 (赵中) C语言指针与汇编语言地址.
第一单元 初识C程序与C程序开发平台搭建 ---观其大略
第3章 堆栈和队列 堆栈 堆栈应用 队列 队列应用 优先级队列 主要知识点.
内容回顾 线性表的定义和特点 线性表的顺序存储及查找、插入和删除.
第8章 结 构 体.
线性表练习.
用event class 从input的root文件中,由DmpDataBuffer::ReadObject读取数据的问题
顺序表的插入.
3.1 线性表及逻辑结构 3.2 线性表的顺序存储 3.3 线性表的链式存储 3.4 链式存储结构的应用
C++语言程序设计 C++语言程序设计 第七章 类与对象 第十一组 C++语言程序设计.
第十章 用户自定义数据类型 目录 学生信息管理系统的开发 结构体数据类型的概述 结构体变量的使用 结构体数组
第十章 结构体与链表 西安工程大学.
顺序表的删除.
本节内容 随机读取 视频提供:昆山爱达人信息技术有限公司.
Linked Lists Prof. Michael Tsai 2013/3/12.
VB与Access数据库的连接.
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
单链表的基本概念.
<编程达人入门课程> 本节内容 内存的使用 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群: ,
第 四 讲 线性表(二).
本教學投影片係屬教科書著作之延伸,亦受著作權法之保護。
多层循环 Private Sub Command1_Click() Dim i As Integer, j As Integer
C++语言程序设计 C++语言程序设计 第六章 指针和引用 第十一组 C++语言程序设计.
本节内容 指针类型.
第十一章 链表.
第4章 鏈結串列(Linked Lists) 4-1 動態記憶體配置-(6) 4-2 鏈結串列的基礎-(7)
实验目的:掌握数据的顺序存储结构及它们在计算机中的操作。 实验内容:
基于列存储的RDF数据管理 朱敏
C++语言程序设计 C++语言程序设计 第一章 C++语言概述 第十一组 C++语言程序设计.
C语言程序设计 第9章 结构体.
C++语言程序设计 C++语言程序设计 第九章 类的特殊成员 第十一组 C++语言程序设计.
算法3.3 void InitList_sq(SqList &L,int msize=LIST_INIT_SIZE)
Chapter 2 Entity-Relationship Model
第9章 C++程序设计初步 9.1 C++的特点 9.2 最简单的C++程序 9.3 C++的输入输出 9.4 函数的重载
本节内容 指针类型 视频提供:昆山爱达人信息技术有限公司 官网地址: 联系QQ: QQ交流群 : 联系电话:
第二章 线性表 东南大学计算机学院 方效林 本课件借鉴了清华大学殷人昆老师 和哈尔滨工业大学张岩老师的课件.
安排座位.
Presentation transcript:

第15讲 链表 计算机与通信工程学院

第15讲 链表 本讲主要内容 链表概述 链表的概念 链表的特点; 定义链表结构; 链表的基本操作 链表结点的插入 链表结点的删除 链表结点的查找 Josephus问题

第15讲 链表 教学目标 了解链表的概念、特点。 能熟练定义链表的结点结构,熟悉建立链表的一般过程。 掌握链表结点的插入、删除、查找等基本操作方法。 能使用链表进行简单的数据管理。

一、链表概述 链表的概念 链表是结构体最重要的应用,它是一种非固定长度的数据结构,是一种动态存储技术,它能够根据数据的结构特点和数量使用内存,尤其适用于数据个数可变的数据存储。 使用链表存储数据的原理与数组不同,它不需要事先说明要存储的数据数量,系统也不会提前为它准备大的存储空间,而是当需要存储数据时,通过动态内存分配函数malloc()或calloc()向系统获取一定数量的内存,用于数据存储。需要多少,就申请多少,系统就分配多少。

一、链表概述 实例:使用链表存储表13-1中前3个学生数据。 构成链表的每一个独立的内存段称为一个链表结点,结点中存储数据的部分称为结点数据域,存储下一个结点地址的部分称为结点指针域,指向第一个结点的指针称为链表的头指针。

一、链表概述 链表的特点 链表作为一种动态的数据结构,具有如下特点: ⑴ 链表中的结点具有完全相同的结构,每一个存储一个独立的结构体数据; ⑵ 链表的结点由系统随机分配,它们在内存中的位置可能是相邻的,也可能是不相邻的,结点之间的联系是通过指针域实现的; ⑶ 为了能准确的定位第一个结点,每个链表要有一个表头指针,从第一个结点开始,沿指针链能遍历链表中的所有结点; ⑷ 链表中的结点是在需要时用calloc()申请的,当不再需要时,应有free()函数释放所占用的内存段。 ⑸ 一个链表不需要事先说明它要包括的结点数目,在需要存储新的数据时,就可增加结点,需要删除数据时,就减少结点,链表结点是动态变化的。

一、链表概述 定义链表结构 要定义一个链表结点的结构,需要包括两个方面: 一方面定义数据存储所对应的各个成员; 另一方面定义指向其他结点的指针成员。 例如,假若要用链表逐个存储一批整数, 其结点结构可定义如下: struct node { int data; struct node *next; /* 指向struct node类型的指针 */ };

一、链表概述 定义链表结构 前面实例(使用链表存储表13-1中前3个学生数据) 的结点结构可定义如下: struct student { int num; /* 学号 */ char name[20]; /* 姓名 */ char sex; /* 性别 */ int age; /* 年龄 */ float score; /* 成绩 */ char addr; /* 地址 */ struct student *next;/* 指向struct student类型的指针 */ }; 其中,num、name、sex、age、score、addr是结点数据域的成员,next是结点指针域的成员。

一、链表概述 生成一个链表结点的一般过程: ⑴ 向系统申请一个内存段,其大小由结点的数据类型决定。例如,calloc(1,sizeof(struct node)) 。 ⑵ p=(结点数据类型 *)calloc(1,sizeof(结点数据类型)); 例如,可使用如下形式申请一个struct node类型的结点: p=(struct node *)calloc(1,sizeof(struct node)); ⑶ 为申请得到的结点添加数据。

二、链表的基本操作 链表结点的插入 在链表中插入结点,就是把一个新结点连接到链表中。通常有两种情况: 一种情况是在空链表中插入一个结点,此时,插入的结点既是链表的第一个结点,也是链表的最后一个结点; 另一种情况是在链表的p结点之后插入一个新结点。

new=(struct node *)calloc(1,sizeof(struct node)); 二、链表的基本操作 在空链表中插入一个结点 空链表就是头指针head为空的链表。 ⑴ 用如下语句申请一个new结点: new=(struct node *)calloc(1,sizeof(struct node)); ⑵ 为p结点填充数据:将要存储的数据对应传给p结点数据域的各个成员; ⑶ 修改有关指针的指向: ①将head指向new结点。 ②将new的next成员置空,使new结点成为链表的最后一个结点; …… struct node *new; new=(struct node *)calloc(1,sizeof(struct node)); new->data=m; head=new; head->next=NULL;  ……

二、链表的基本操作 在head链表的p结点之后插入一个结点 设head链表和要插入结点new如下图所示。要将new结点插入在p结点之后,就是将new结点变成结点C的下一个结点,而使new的下一个结点成为结点D。 对new和p结点的指针域进行如下操作: ⑴ 使new的指针域存储结点D的首地址: new->next=p->next; ⑵ 把new的首地址存储到结点p的指针域中: p->next=new;

二、链表的基本操作 如下是在head链表的p结点之后插入值为m的结点的函数insert(),函数的返回值是链表的头指针: #include "malloc.h" #include "stdio.h" struct student *insert(struct node *head,struct node *p,int m) {struct node *new; new=(struct node *)calloc(1,sizeof(struct node)); new->data=m; if(head==NULL) { head=new; head->next=NULL;} else { new->next=p->next; p->next=new; } return(head); }

二、链表的基本操作 例14-1 用插入结点的方法建立下图所示的学生成绩链表,链表head有10个结点,每个结点存储一个学生的学号和学习成绩数据。 struct s_node *creat_node(void) {struct s_node *p; float score; fflush(stdin); p=(struct s_node *)calloc(1, sizeof(struct s_node)); gets(p->num); scanf("%f",&score); p->score=score; p->next=NULL; return(p); } #include "stdio.h" #define N 5 struct s_node {char num[4]; float score; struct s_node *next; }; main() { struct s_node *creat_node(void); struct s_node *creat_list(int n); void out_list(struct s_node *head); struct s_node *head=NULL; head=creat_list(N); out_list(head); }

二、链表的基本操作 struct s_node *creat_list(int n) {struct s_node *new,*p; struct s_node *head; int i; if(n>=1) { new=creat_node(); head=new; p=new;} for(i=2;i<=n;i++) p->next=new; return(head); else return(NULL); } void out_list(struct s_node *head) {struct s_node *p; if(head!=NULL) { p=head; while(p!=NULL) { printf("%s %f\n",p->num, p->score); p=p->next; } }

二、链表的基本操作 链表结点的删除 在链表中删除结点一般有两个过程: 一是把指定的结点从链表中拿下来,它需要通过修改有关结点的指针域来完成; 二是释放该结点使用的内存空间,它需要使用free()函数来实现。

二、链表的基本操作 上图是一个head链表,删除p结点的过程如下: ⑴ 若p结点是链表的第一个结点,则将p指针域的地址保存到head中,使p的后继结点成为head链表的第一个结点,然后转步骤⑶。修改指针的操作如下: head=head->next;或 head=p->next; ⑵ 若p结点不是链表的第一个结点,则首先从head开始,找到p结点的前一个结点q,然后使q的指针域存储p的后继结点的地址,这样沿链表的指针访问链表中的结点时,p结点将不会被访问到,亦即p结点从链表head中被删除了。链表指针的修改操作如下: q->next=p->next; ⑶ 释放p结点使用的内存空间。操作如下:free(p);

二、链表的基本操作 如下是在head链表中删除p结点的delete()函数: #include "stdio.h" void delete(struct node *head,struct node *p) {struct node *q; q=head; if(p==head) head=head->next; /* p是第一个结点是,修改链表的头指针 */ else { while(q->next!=p) /* 找到p的前一个结点的地址 */ q=q->next; q->next=p->next; /* 删除p结点 */ } free(p); /* 释放p结点占用的内存 */

二、链表的基本操作 链表结点的查找 在链表中进行查找,就是从链表的第一个结点开始,沿着指针链,用查找值与链表结点逐个比较的过程。找到符合要求的结点之后,停止查找过程,返回相应结点的指针,否则返回一个空指针。如下是在head链表中查找data值为m的结点的过程,其中p为struct node型指针: ⑴ p=head; ⑵ 当p≠NULL时,若p->data==m,则找到要求结点,查找结束,返回结点地址p;否则,执行下一步⑶;当p== NULL时,链表中不存在要找的结点,查找结束,返回空指针NULL; ⑶ p=p->next;/* 将p指向下一个结点 */ ⑷ 重复⑵、⑶步骤。

二、链表的基本操作 #include "stdio.h" 链表结点的查找函数find()设计如下: #include "stdio.h" struct node *find(struct node *head,int m) {struct node *p=head; while(p!=NULL&&p->data!=m) p=p->next; if(p==NULL) return(NULL) else return(p); }

二、链表的基本操作 例14-2 对如下图所示的head链表,删除其值是x的结点。具体要求如下:⑴ 输出被删除结点的值;⑵ 当指定值结点不存在时,显示一个提示信息;⑶ x的值由键盘输入。 该问题的关键点有两点: 第一是查找data等于x的结点p; 第二是删除p结点。 需要注意的是,p结点删除之后,要将其使用的内存释放。

二、链表的基本操作 #include "stdio.h" struct node { int data; struct node *next; }; struct node *find_x( struct node *head,int x) {struct node *p,*q; p=q=head; while(p!=NULL&&p->data!=x) { q=p; p=p->next; } if(p==NULL) return(NULL); else return(q); void delete_p( struct node *head, struct node *p) {struct node *q; if(p==NULL) { printf("no found\n"); return; } if(p==head) { head=p->next; q=p;} else { q=p->next; p->next=q->next;} printf("\ndelete: %d\n", q->data); free(q); }

二、链表的基本操作 struct node *creat_number(int n) {int i; struct node *head,*new,*p; if(n>=1) { new=(struct node*)malloc( sizeof(struct node)); new->data=1; new->next=NULL; head=new; p=new;} for(i=2;i<=n;i++) new->data=i; p->next=new; if(n>=1) return(head); else return(NULL); } main() {int n,x; struct node *head,*p; printf("Enter n,x: "); scanf("%d,%d",&n,&x); head=creat_number(n); p=find_x(head,x); delete_p(head,p); }

二、链表的基本操作 Josephus问题 例14-3 Josephus问题:有n个人围成一圈,从1开始顺序编号到n,现在从1号开始顺时针从1数数,数到m者自动出列,然后从下一个人开始重新数数,仍然每次数到m者自动出列。请给出这n个人出列的顺序。 我们用下图所示的链表解决Josephus问题,head链表从第一个结点开始依次存储n个人的编号,但与其他链表不同的是,它最后一个结点的指针域没有存储空指针,而是存放了第一个结点的地址,使得链表在链路上形成了一个环,这样的链表称为循环链表。

二、链表的基本操作 #include "stdio.h" #include "alloc.h" struct circle {int number; struct circle *next; }; struct circle *creat_j(int n) {int i; struct circle *head,*new,*p; new=(struct circle*)malloc( sizeof(struct circle)); new->number=1; head=new; p=new; for(i=2;i<=n;i++) { new=(struct circle*)malloc( new->number=i; p->next=new; p=new; } p->next=head; return(head); } void josephus( struct circle *head,int m) {struct circle *p,*q,*temp; int i=1; q=p=head; while(p!=p->next) { if(i==m) { printf("%5d", p->number); q->next=p->next; temp=p; p=p->next; free(temp); i=1;} else { q=p; i++;} } printf("%5d\n",p->number);

二、链表的基本操作 main() {int n,m; struct circle *head; printf("Enter n,m: "); scanf("%d,%d",&n,&m); head=creat_j(n); josephus(head,m); } 如下是程序的一个执行结果: Enter n,m: 10,5 5 10 6 2 9 8 1 4 7 3

链表-小结 1.链表是一种动态的数据存储结构,它的每一个结点都是结构体类型的数据,同一个链表中的所有结点具有相同的数据类型。 2.一个链表结点分为数据域和指针域两部分,数据域存储需要处理的数据,指针域存储下一个结点的位置。链表结点在物理位置上没有相邻性,结点之间的联系通过指针实现。 3.对链表施行的基本操作有插入结点、删除结点、查找结点、结点数据读写等,向链表插入结点前必须先用动态内存分配函数获得结点,从链表中删除的结点要进行释放操作。 4.从空链表开始不断地插入结点即可建立一个链表,任何一个链表必须有一个头指针,只有通过头指针才能访问链表结点。当一个链表结点的指针域为空时,表明是链表的最后一个结点,当最后一个结点的指针指向开头结点时,便形成一个循环链表。