内容回顾 线性表的定义和特点 线性表的顺序存储及查找、插入和删除.

Slides:



Advertisements
Similar presentations
詹天佑 詹天佑(1861—1919),江西婺wu源人。我国杰出的爱国工程师、铁路工程专家。毕业于美国耶鲁大学。他是中国首位铁路工程师,负责修建了京张铁路(北京——张家口)等铁路工程,有“中国铁路之父”、“中国近代工程之父”之称。
Advertisements

天净沙·秋思 马致远 枯藤老树昏鸦, 小桥流水人家, 古道西风瘦马。 夕阳西下, 断肠人在天涯。
数据结构概论 第2章 线性表 董黎刚 浙江工商大学信电学院
死與生的自我掌握.
組長:黃家逸 組員:殷浩賢、楊煜、吳家朗 毒品的害處.
数据结构——树和二叉树 1/96.
第六章 树和二叉树.
数据结构算法 模拟练习及解答二 绍兴文理学院 计算机系计算机应用教研室.
第8章 查找 在英汉字典中查找某个英文单词的中文解释;在新华字典中查找某个汉字的读音、含义;在对数表、平方根表中查找某个数的对数、平方根;邮递员送信件要按收件人的地址确定位置等等。可以说查找是为了得到某个信息而常常进行的工作。 计算机、计算机网络使信息查询更快捷、方便、准确。要从计算机、计算机网络中查找特定的信息,就需要在计算机中存储包含该特定信息的表。如要从计算机中查找英文单词的中文解释,就需要存储类似英汉字典这样的信息表,以及对该表进行的查找操作。本章将讨论的问题即是“信息的存储和查找”。
数据结构 第6章 树和二叉树 什么是树和二叉树?? 二叉树的遍历 数据结构.
第二章 线性表 1 线性表的逻辑结构及其基本操作 2 线性表的顺序存储结构 3 线性表的链式存储结构 4 静态链表 5 应用实例.
第二章 线性表.
第2章 线性表 2.1 线性表的概念及运算 2.2 线性表的顺序存储 2.3 线性表的链式存储 2.4 一元多项式的表示及相加.
第九章 系 统 安 全 性 9.1 结构体 9.2 结构体型数组  9.3 结构体型指针 9.4 内存的动态分配 9.5 共用体
Linked List(串列) Why Linked List? Pointer Dynamic Allocation
Linked List Operations
第3章 栈和队列 3.1 栈 3.2 队列 3.3 应用.
單向鏈結串列 Singly Linked Lists.
第2章 线性表 线性结构 是一个数据元素的有序集合。.
第6章 佇列(Queues) 6-1 佇列的基礎 6-2 佇列的表示法 6-3 環狀佇列 6-4 雙佇列.
第7章 结构体、联合体和枚举类型 本章导读 本章主要知识点 《 C语言程序设计》 (Visual C++ 6.0环境)
第11章 查找 主要知识点 查找的基本概念 静态查找表 动态查找表 哈希表.
資料結構 第5章 佇列.
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
第三章 线性表 3.1 线性表的类型定义 3.2 顺序存储的线性表 3.3 链式存储的线性表 3.4 有序表 3.5 顺序表和链表的综合比较.
第五章 数组和广义表.
·线性表的定义及ADT ·线性表的顺序存储结构 ·线性表的链接存储结构 · 单向循环链表 · 双链表、双向循环链表 · 一元多项式的加法
第2章 线性表(三) 1/.
第12章 樹狀搜尋結構 (Search Trees)
Ch.3 栈和队列 黄刘生 中国科学技术大学计算机系 国家高性能计算中心(合肥)
线性表小结 元素之间的线性关系 顺序表 顺序表:元素相邻存储 单链表:后继指针链接 一维数组 给定下标随机存取
cn/~dongeliu/dsa.html 刘 东 信息学院6系 中国科学技术大学
第2章 线性表 2.1 线性表的基本概念 2.2 线性表的顺序存储 2.3 线性表的链式存储 2.4 线性表的应用 2.5 有序表 本章小结.
第3章 栈和队列(二) 1/.
第2章 线性表 线性表抽象数据类型 顺序表 主要知识点 单链表 循环单链表 循环双向链表 静态链表 设计举例.
第十章 C高级程序应用—链表* 10.1链表的基本概念 10.2单向链表 10.3双向链表 10.4应用举例.
第3章 堆栈和队列 堆栈 堆栈应用 队列 队列应用 优先级队列 主要知识点.
第八章 查找表 8.1静态查找表 8.2动态查找表 8.3哈希表及其查找.
本章重点难点 重点:顺序查找、二分查找、二叉排序树查找以及散列表查找的基本思想和算法实现。
第 3 讲 线性表(一).
第三章 栈与队列 £3.1 栈 £3.3 队列 £3.2 栈的应用举例 £3.1.1 栈的定义 £3.1.2 栈的顺序存储结构
第三章 栈和队列 3.1 栈 3.2 栈的应用举例 3.3 栈与递归的实现 3.4 队列.
第3章 栈和队列(一).
第三章 栈和队列.
数据结构 Data Structure 中南大学 主讲人:王国军,郑瑾 中南大学信息院计科系
第二章 线性表.
資料結構與C++程式設計進階 堆疊與佇列(Stack & Queue) 講師:林業峻 CSIE, NTU 6/ 21, 2010.
第一章 绪论.
五、链 表 1、单链表 2、双向链表 3、链表应用.
教 师:曾晓东 电 话: E_mail: 计算机软件技术基础 教 师:曾晓东 电 话: E_mail:
陈海明 副教授 信息学院 计算机系 电子信息类非计算机专业选修课 程序设计实践 陈海明 副教授 信息学院 计算机系
第九章 查找表 9.1静态查找表 9.2动态查找表 9.3哈希表及其查找.
第九章 查找 2019/2/16.
第三章 栈和队列.
#define STACK_INIT_SIZE 10
严蔚敏、吴伟民编著 清华大学出版社 学习网站:
陈海明 副教授 信息学院 计算机系 电子信息类非计算机专业选修课 程序设计实践 陈海明 副教授 信息学院 计算机系
王玲 第 2 章 线性表 王玲 2019/2/25.
3.1 线性表及逻辑结构 3.2 线性表的顺序存储 3.3 线性表的链式存储 3.4 链式存储结构的应用
第十章 结构体与链表 西安工程大学.
第六章 树和二叉树 学习要点 理解树的定义和基本术语,重点了解二叉树的定义、性质、存储结构; 掌握二叉树遍历的递归算法及它的典型运算;
Linked Lists Prof. Michael Tsai 2013/3/12.
第 四 讲 线性表(二).
本教學投影片係屬教科書著作之延伸,亦受著作權法之保護。
第二章 线性表.
第 六 讲 栈和队列(一).
第三章 线性表 3.1 线性表的类型定义 3.2 顺序存储的线性表 3.3 链式存储的线性表 3.4 有序表 3.5 顺序表和链表的综合比较.
算法3.3 void InitList_sq(SqList &L,int msize=LIST_INIT_SIZE)
Chapter 2 Entity-Relationship Model
本节内容 1.二叉排序树的定义 2.二叉排序树的查找操作 3.二叉排序树的插入操作 4.二叉排序树的删除操作 5.二叉排序树的总结
Presentation transcript:

内容回顾 线性表的定义和特点 线性表的顺序存储及查找、插入和删除

教学目标 第2章 线性表 1. 了解线性结构的特点 2.掌握顺序表的定义、查找、插入和删除 3.掌握链表的定义、创建、查找、插入和删除 第2章 线性表 教学目标 1. 了解线性结构的特点 2.掌握顺序表的定义、查找、插入和删除 3.掌握链表的定义、创建、查找、插入和删除 4.能够从时间和空间复杂度的角度比较两种存储结构的不同特点及其适用场合

教学内容 2.1 线性表的定义和特点 2.2 案例引入 2.3 线性的类型定义 2.4 线性表的顺序表示和实现 2.2 案例引入 2.3 线性的类型定义 2.4 线性表的顺序表示和实现 2.5 线性表的链式表示和实现 2.6 顺序表和链表的比较 2.7 线性表的应用 2.8 案例分析与实现

2.5 .1线性表的链式表示和实现 链式存储结构 结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻 如何实现? 线性表的链式表示又称为非顺序映像或链式映像。 如何实现? 通过指针来实现

例 画出26 个英文字母表的链式存储结构 逻辑结构:( a, b, … ,y, z) 链式存储结构: 各结点由两个域组成: 例 画出26 个英文字母表的链式存储结构 逻辑结构:( a, b, … ,y, z) 链式存储结构: a head b /\ z …… 各结点由两个域组成: 数据域:存储元素数值数据 指针域:存储直接后继结点的存储位置 指针 数据

与链式存储有关的术语 1、结点:数据元素的存储映像。由数据域和指针域两部分组成 2、链表: n 个结点由指针链组成一个链表。它是线性表的链式存储映像,称为线性表的链式存储结构

循环链表示意图: 3、单链表、双链表、循环链表: 结点只有一个指针域的链表,称为单链表或线性链表 有两个指针域的链表,称为双链表 首尾相接的链表称为循环链表 循环链表示意图: a1 head a2 an ……

4、头指针、头结点和首元结点 头指针 头结点 首元结点 头指针是指向链表中第一个结点的指针 首元结点是指链表中存储第一个数据元素a1的结点 head a2 … info an ^ 头指针是指向链表中第一个结点的指针 首元结点是指链表中存储第一个数据元素a1的结点 头结点是在链表的首元结点之前附设的一个结点;数据域内只放空表标志和表长等信息

上例链表的逻辑结构示意图有以下两种形式: ① ZHAO QIAN LI SUN ZHOU WU ZHENG /\ WANG H ② ZHAO QIAN LI SUN ZHOU WU ZHENG /\ WANG H 区别:① 无头结点 ② 有头结点

有头结点时,当头结点的指针域为空时表示空表 讨论1. 如何表示空表? 有头结点时,当头结点的指针域为空时表示空表 非空表 空表 an a0 head ^ 表头结点 第一个结点

首元结点的地址保存在头结点的指针域中,所以在链表的第一个位置上的操作和其它位置一致,无须进行特殊处理; 讨论2. 在链表中设置头结点有什么好处? ⒈便于首元结点的处理 首元结点的地址保存在头结点的指针域中,所以在链表的第一个位置上的操作和其它位置一致,无须进行特殊处理; ⒉便于空表和非空表的统一处理 无论链表是否为空,头指针都是指向头结点的非空指针,因此空表和非空表的处理也就统一了。

讨论3. 头结点的数据域内装的是什么? 头结点的数据域可以为空,也可存放线性表长度等附加信息,但此结点不能计入链表长度值。 H 头结点的数据域

链表(链式存储结构)的特点 (1)结点在存储器中的位置是任意的,即逻辑上相邻的数据元素在物理上不一定相邻 (2)访问时只能通过头指针进入链表,并通过每个结点的指针域向后扫描其余结点,所以寻找第一个结点和最后一个结点所花费的时间不等  这种存取元素的方法被称为顺序存取法

链表的优缺点 优点 数据元素的个数可以自由扩充 插入、删除等操作不必移动数据,只需修改链接指针,修改效率较高 缺点 存储密度小 存取效率不高,必须采用顺序存取,即存取数据元素时,只能按链表的顺序进行访问(顺藤摸瓜)

练习-指出错误之处 1.链表的每个结点中都恰好包含一个指针。 2.顺序表结构适宜于进行顺序存取,而链表适宜于进行随机存取。 3.顺序存储方式的优点是存储密度大,且插入、删除运算效率高。 4.线性表若采用链式存储时,结点之间和结点内部的存储空间都是可以不连续的。 5.线性表的每个结点只能是一个简单类型,而链表的每个结点可以是一个复杂类型 ( × )1. 链表的每个结点中都恰好包含一个指针。 答:错误。链表中的结点可含多个指针域,分别存放多个指针。例如,双向链表中的结点可以含有两个指针域,分别存放指向其直接前趋和直接后继结点的指针。

单链表的定义和实现 非空表 空表 单链表是由表头唯一确定,因此单链表可以用头指针的名字来命名 若头指针名是L,则把链表称为表L

单链表的存储结构定义 typedef struct LNode{ ElemType data; //数据域 struct LNode *next; //指针域 }LNode,*LinkList; // *LinkList为Lnode类型的指针 LNode *p LinkList p 结点空间的申请 p=(LNode*)malloc(sizeof(LNode))----对指针p赋值使其指向某一结点(按需生成一个LNode结点类型的新结点)。 其中:(LNode*)----进行类型转换。 Sizeof(LNode)---求结点需用占用的字节数。 malloc(size)--在内存中分配size个连续可用字节的空间。 free(p)--系统回收p结点。(动态)

LNode *p 注意区分指针变量和结点变量两个不同的概念 指针变量p:表示结点地址 结点变量*p:表示一个结点 若p->data=ai, 则p->next->data=ai+1

2.5.2 单链表基本操作的实现 1. 初始化 2. 取值 3. 查找 4. 插入 删除 创建

1.初始化(构造一个空表 ) 【算法步骤】 (1)生成新结点作头结点,用头指针L指向头结点。 (2)头结点的指针域置空。 【算法描述】 Status InitList_L(LinkList &L){ L=(LinkList)malloc(sizeof(LNode)); L->next=NULL;      return OK; }

1.初始化(构造一个空表 ) LinkList Creat_LinkList(void ) { /*创建空单链表,入口参数:无;返回值:单链表的头指针,0代表创建失败,非0表成功*/ LinkList L; L=(LinkList)malloc(sizeof(LNode)); if (L) /*确认创建头结点创建是否成功,若成功,修改单链表头结点的指针域为0表空表*/ L->next=NULL; return L; }

2. 取值(根据位置i获取相应位置数据元素的内容) 链表的查找:要从链表的头指针出发,顺着链域next逐个结点往下搜索,直至搜索到第i个结点为止。因此,链表不是随机存取结构

例:分别取出表中i=3和i=15的元素 L i=3 i=15 21 18 30 75 42 56 ∧ p p p p p p j 6 7 1 3 2 1 【算法步骤】 从第1个结点(L->next)顺链扫描,用指针p指向当前扫描到的结点,p初值p = L->next。 j做计数器,累计当前扫描过的结点数,j初值为1。 当p指向扫描到的下一结点时,计数器j加1。 当j = i时,p所指的结点就是要找的第i个结点。 85

2. 取值(根据位置i获取相应位置数据元素的内容) //获取线性表L中的某个数据元素的内容 Status GetElem_L(LinkList L,int i,ElemType &e){ //初始化 p=L->next;j=1; //向后扫描,直到p指向第i个元素或p为空 while(p&&j<i){ p=p->next; j++; } //第i个元素不存在 if(!p || j>i)return ERROR; //取第i个元素 e=p->data; return OK; }//GetElem_L

L 21 18 30 75 30 56 p p p p p p j 1 1 3 2 7 6 3.查找(根据指定数据获取数据所在的位置) x=30 x=51 21 18 30 75 30 56 ∧ p p p p p p j 1 1 3 2 7 6 未找到,返回0 找到,返回i 从第一个结点起,依次和e相比较。 如果找到一个其值与e相等的数据元素,则返回其在链表中的“位置”或地址; 如果查遍整个链表都没有找到其值和e相等的元素,则返回0或“NULL”。

【算法描述】 //在线性表L中查找值为e的数据元素 LNode *LocateELem_L (LinkList L,Elemtype e) { //返回L中值为e的数据元素的地址,查找失败返回NULL p=L->next; while(p &&p->data!=e) p=p->next; return p; }

【算法描述】 //在线性表L中查找值为e的数据元素 int LocateELem_L (LinkList L,Elemtype e) { p=L->next; j=1; while(p &&p->data!=e) {p=p->next; j++;} if(p) return j; else return 0; }

s->next=p->next; p->next=s 3. 插入(插在第 i 个结点之前) 将值为x的新结点插入到表的第i个结点的位置上,即插入到ai-1与ai之间 s->next=p->next; p->next=s 思考:步骤1和2能互换么?

【算法步骤】 (1)找到ai-1存储位置p (2)生成一个新结点*s (3)将新结点*s的数据域置为x (4)新结点*s的指针域指向结点ai 12:00

【算法描述】 //在L中第i个元素之前插入数据元素e Status ListInsert_L(LinkList &L,int i,ElemType e){ p=L;j=0; //寻找第i−1个结点 while(p&&j<i−1){p=p->next; j ++;} if(!p||j>i−1)return ERROR; //i大于表长 + 1或者小于1 //生成新结点s ,将结点s的数据域置为e s=(LinkList)malloc(sizeof(LNode)); s->data=e; //将结点s插入L中 s->next=p->next; p->next=s; return OK; }//ListInsert_L

p->next = p->next->next ??? 5. 删除(删除第 i 个结点)  ai-1  ai ai+1 删除前  ai-1 ai ai+1  p q 删除后 p->next = p->next->next ???

【算法步骤】 (1)找到ai-1存储位置p (2)临时保存结点ai的地址在q中,以备释放 (3)令p->next指向ai的直接后继结点 (4)将ai的值保留在e中,并释放ai的空间

【算法描述】 //将线性表L中第i个数据元素删除 Status ListDelete_L(LinkList &L,int i,ElemType &e){ p=L;j=0; while(p->next &&j<i-1){//寻找第i个结点,并令p指向其前驱 p=p->next; ++j; } if(!(p->next)||j>i-1) return ERROR; //删除位置不合理 q=p->next; //临时保存被删结点的地址以备释放 p->next=q->next; //改变删除结点前驱结点的指针域 e=q->data; //保存删除结点的数据域 free(q); //释放删除结点的空间 return OK; }//ListDelete_L

链表的运算时间效率分析 1. 查找: 因线性链表只能顺序存取,即在查找时要从头指针找起,查找的时间复杂度为 O(n)。

单链表的建立(前插法) 从一个空表开始,重复读入数据: 生成新结点 将读入数据存放到新结点的数据域中 将该新结点插入到链表的前端

p->data=an p->data=an-1 6.单链表的建立(前插法) p->next= L->next L->next=p p->next= L->next p->data=an p->data=an-1

【算法描述】 void CreateList_F(LinkList &L,int n){ L =(LinkList)malloc(sizeof(LNode)); L->next=NULL; //先建立一个带头结点的单链表 for(i=n;i>0;--i){ p =(LinkList)malloc(sizeof(LNode)); //生成新结点 scanf(p->data); //输入元素值 p->next=L->next;L->next=p; //插入到表头 } }//CreateList_F

6.单链表的建立(尾插法) 从一个空表L开始,将新结点逐个插入到链表的尾部,尾指针r指向链表的尾结点。 初始时,r同L均指向头结点。每读入一个数据元素则申请一个新结点,将新结点插入到尾结点后,r指向新结点。

【算法描述】 void CreateList_L(LinkList &L,int n){ //正位序输入n个元素的值,建立带表头结点的单链表L L =(LinkList)malloc(sizeof(LNode)); L->next=NULL; r=L; //尾指针r指向头结点 for(i=0;i<n;++i){ p =(LinkList)malloc(sizeof(LNode)); //生成新结点 scanf(p->data); //输入元素值 p->next=NULL; r->next=p; //插入到表尾 r=p; //r指向新的尾结点 } }//CreateList_L

2.5.3 循环链表 (a) 非空单循环链表 L (b) 空表 L L->next=L

说明 从循环链表中的任何一个结点的位置都可以找到其他所有结点,而单链表做不到; 循环链表中没有明显的尾端 如何避免死循环 循环条件:p!=NULLp!=L p->next!=NULLp->next!=L

说明 对循环链表,有时不给出头指针,而给出尾指针 可以更方便的找到第一个和最后一个结点 rear a1 ai-1 an ai 如何查找开始结点和终端结点? 开始结点:rear->next->next 终端结点:rear

循环链表的合并 ① p ② ③ ④ a1 an b1 bn Ta Tb LinkList Connect(LinkList Ta,LinkList Tb) {//假设Ta、Tb都是非空的单循环链表 //①p存表头结点 //②Tb表头连结Ta表尾 //③释放Tb表头结点 //④修改指针 return Tb; } p=Ta->next; Ta->next=Tb->next->next; free(Tb->next); Tb->next=p;

2.5.4 双向链表 typedef struct DuLNode{ ElemType data; struct DuLNode *prior; struct DuLNode *next; }DuLNode, *DuLinkList

L->next=L p->next->prior = p->prior->next = p (a) 空双向循环链表 L->next=L (b) 双向循环链表 p->next->prior = p->prior->next = p

1. s->prior=p->prior; 2. p->prior->next=s; 双向链表的插入 p ... ... a b 1 2 4 3 x s 1. s->prior=p->prior; 2. p->prior->next=s; 3. s->next=p; 4. p->prior=s;

双向链表的插入 Status ListInsert_DuL(DuLinkList &L,int i,ElemType e){ if(!(p=GetElemP_DuL(L,i))) return ERROR; s =(LinkList)malloc(sizeof(LNode)); s->data=e; s->prior=p->prior; p->prior->next=s; s->next=p; p->prior=s; return OK; }

1. p->prior->next=p->next; 双向链表的删除 1. p->prior->next=p->next; 2. p->next->prior=p->prior;

双向链表的删除 Status ListDelete_DuL(DuLinkList &L,int i,ElemType &e){ if(!(p=GetElemP_DuL(L,i))) return ERROR; e=p->data; p->prior->next=p->next; p->next->prior=p->prior; delete p; return OK; }

2.6 顺序表和链表的比较 存储结构 比较项目 顺序表 链表 空间 存储空间 预先分配,会导致空间闲置 或溢出现象 预先分配,会导致空间闲置 或溢出现象 动态分配,不会出现存储 空间闲置或溢出现象 存储密度 不用为表示结点间的逻辑关 系而增加额外的存储开销, 存储密度等于1 需要借助指针来体现元素 间的逻辑关系,存储密度 小于1 时间 存取元素 随机存取,按位置访问元素 的时间复杂度为O(1) 顺序存取,按位置访问元 素时间复杂度为O(n) 插入、删除 平均移动约表中一半元素, 时间复杂度为O(n) 不需移动元素,确定插入、 删除位置后,时间复杂度 为O(1) 适用情况 ① 表长变化不大,且能事先 确定变化的范围 ② 很少进行插入或删除操作, 经常按元素位置序号访问数 据元素 ① 长度变化较大 ② 频繁进行插入或删除操 作

小结 1. 熟练掌握线性表链式存储结构的特点。 2. 掌握单链表的基本操作的实现方法。 3. 理解循环链表的存储结构的特点; 4. 掌握双向链表的存储结构和基本操作的实现。

作业 编写程序创建一个保存学生基本信息的单链表,实现学生信息的插入、删除、查看等功能。 实验一:线性表的操作及应用