数据结构课件第2章线性表B

合集下载

《数据结构》课件第二章

《数据结构》课件第二章

线性表的基本操作(逻辑)
➢ 构造一个空表L ➢ 获取L的长度(即元素个数) ➢ 访问L中第i个数据元素的值 ➢ 访问L中第i个数据元素的前驱/后继的值 ➢ 在L中第i个元素之前插入新的元素e ➢ 删除L的第i个数据元素
➢ 注意在插入或者删除之后,线性表的长度应 能随之改变
一 顺序存储
➢ 线性表的顺序表示:用一组地址连续的存储单 元依次存储线性表的数据元素。

将Temp_b插入到 LC的第k个位置上
Temp_a ≤ Temp_b
是 将Temp_a插入到 LC的第k个位置上
否 i ≤ LA.len 否
j← j + 1
i← i + 1
j ≤ LB.len
Temp_a = Temp_b



j← j + 1
k← k + 1
结束

将LA表的第i个元 素插入到LC表的
插入操作的时间复杂度 O(n/2) 链表中的插入、删除操作没有上溢的情况, 并且节省内存资源
思考:若现已知道指向某元素节点的指针 p,希望能在该节点之前插入元素x,该如 何操作?其算法时间复杂度是多少?
3) 单链表的删除
p
删除第i个元素,由e返回值 删除b
a
Hale Waihona Puke bc … 1) 寻找第i-1个结点
2) 保留结点b的地址
9 SHI 5
0
1
1 ZHAO 2
2 QIAN 3
3 SUN 4
4 LI
9
5 ZHOU 6
6 WU 8
7 ZHENG 8
8 WANG 0
9 SHI 5
i=s[i].cur 指针后移

数据结构课件第2章线性表

数据结构课件第2章线性表

27
线性表的顺序存储结构适用于数据 元素不经常变动或只需在顺序存取设备 上做成批处理的场合。为了克服线性表 顺序存储结构的缺点,可采用线性表的 链式存储结构。
28
2.3 线性表的链式存储结构
线性表的链式存储表示 基本操作在单链表上的实现 循环链表 双向链表 线性表链式存储结构小结
2.3.1 线性表的链式存储表示 29
2.1.1 线性表的定义
6
一个线性表(linear_list)是 n(n≥0)个具有相同属性的数 据元素的有限序列,其中各元素有着依次相邻的逻辑关系。
线性表中数据元素的个数 n 称为线性表的长度。当 n = 0 时 该线性表称为空表。当 n > 0 时该线性表可以记为:
(a1,a2,a3,…,ai,…,an)
数据域 指针域
结点 data next
31
(2) 线性表的单链表存储结构
通过每个结点的指针域将线性表中 n 个结点按其逻辑顺序链 接在一起的结点序列称为链表,即为线性表 ( a1, a2, a3, …, ai, …, an ) 的链式存储结构。如果线性链表中的每个结点只有一个指针域, 则链表又称为线性链表或单链表 (linked list)。
17
(2) 算法编写
#define OK 1
#define ERROR 0
Int InsList ( SeqList *L, int i, ElemType e ) /*在顺序线性表 L 中第 i 个位置插入新的元素 e。*/ /* i 的合法值为 1≤i ≤L->last+2*/ {
int k; if ( i < 1) ||( i > L->last+2)) /*首先判断插入位置是否合法*/ { printf(“插入位置i值不合法”);

数据结构之线性表课件

数据结构之线性表课件
实现插入算法主要完成三个基本操作:
1) 在单链表上找到插入位置,即找到第i个结点。 可以用遍历的方法,即从表头起顺次访问单链
表的结点,直至找到第i个结点。 2) 生成一个以x为值的新结点。 可通过C的库函数malloc(size)来产生。 3) 将新结点链入单链表中。 需要改变相关结点的指针 ,如下面的图所示。
H
a1
an ^
空表
……
为了编程方便,一般在单链表的第一个 结点之前加一个“头结点”,如:
head
a1
an ^
当为空表时,即head->next=null, 如下图。
head
^
指针的概念
假设p是一个pointer类型,应正确区分指针型 变量、指针、指针所指的结点和结点的内容 这四个密切相关的不同概念:
2.1线性表的逻辑结构
线性表的定义 线性表是由n个结点a1,a2,…..,an 组成的有 限序列,当n=0时,线性表为空,即为空表。 若n>0, 则a1是第1个结点,an是最后一个结点。
其形式化的定义为: S=(D,R) 其中:D是由n个元素组成的集合, R是定义在集合D上的一种关系。
2.1线性表的逻辑结构
2. 元素的删除(Delete)
在顺序表L=(a1,a2,… ,ai,…,an)中删除第i个结 点,使成为
L=(a1,a2,…,ai-1, ai+1,…, an)
基本思想:要求删除第i个数据元素,由于线性 表元素在数组中必须连续排列,中间不能有空 单元,故将此元素删除后,它后面的所有元素 都需要向前移动一个单元,且数据元素总数由 原来的n减少到n-1.
数据结构之线性表课件
第二章 线性表
知 识 点

数据结构第二章线性表.ppt

数据结构第二章线性表.ppt
构造原理
用一组地址连续的存储单元依次存储线性表的数据元素,数 据元素之间的逻辑关系通过数据元素的存储位置直接反映。
k个单元 (a1,a2,a3,... ...,an)
a1 a2 a3
……
an
LOC(ai)
d1+k=d2 d3
………
dn
所谓一个元素的地址是指该元素占用的
若干(连续的)存储单元的第一个单元的地址。
LOC(a5)=100+(5-1)*4=116
线性表 11
顺序存储结构示意图
(a1,a2,a3,... ...,an)
当前已经占用的空间
尚未使用的空间
a1 a2 a3 … … an-1 an
01 2
n-2 n-1 n
……
n+1
M-1
事先分配给线性表的空间
线性表 12
一般来说,长度为n的线性表(a1,a2,…,an)在计算机中 的结构如下:
INSERT(L,x,i)。 6.删除线性表中第i个数据元素DELETE(L,i)。 7.对线性表中的数据元素进行升序或者降序排序。 8.将两个或两个以上的线性表合并成为一个线性表。 9.将一个线性表分解为两个或两个以上的线性表路】 依次输出线性表中的每个元素的值。
编写在线性表A中删除线性表B中出现的元素的算法。
1 3 57 9
12346
579
【算法思路】 依次检查线性表B中的每个元素,看它是否在线性表
A中。若在A中,则将其从A中删除。
线性表
5
void delete(Sqlist *A,Sqlist *B) {
int i,k;
datatype x;
for(i=1;i<=LENGTH(B);i++) {

《数据结构》课程课件第二章线性表

《数据结构》课程课件第二章线性表

Step2:数据域赋值
插入后: Step3:插入(连接)
X q
(1)式和(2)式的顺序颠倒,可以吗?
4、插入元素(在第i个元素之前插入元素e)
为什么时间复杂度不再是O(1)?
第i-1个元素
第i个元素
p
s
新插入元素
5、删除p所指元素的后继元素
P
删除前:
P->next P->next->next
删除:
五、线性表ADT的应用举例
Void mergelist(list La,list Lb,list &Lc)
{ //已知线性表La和Lb中的数据元素按值非递减排列
//归并La和Lb得到新的线性表Lc,Lc中的元素也按值非递减排列
例: 将两个各有n个元素的有序表归并成一个有序表, 其最小的比较次数是( )。 A、n B、2n-1 C、2n D、n-1
三、线性表的ADT
四、线性表的分类
五、线性表ADT的应用举例
例1:已知有线性表L,要求删除所有X的出现
五、线性表ADT的应用举例
例2: 已知有两个分别有序的线性表(从小到大),要 求合并两个线性表,且合并后仍然有序。——归并 方法1: 合并,再排序O((m+n)2)
方法2: 归并,利用分别有序的特点O((m+n))
二、线性表上常见的运算
8、删除 Delete(L,i):删除线性表的第i个元素 删除前 a1 a2 … ai-1 ai ai+1 … an 删除后 a1 a2 … ai-1 ai+1 … an 9、判断是否为空 Empty(L):线性表空,则返回TRUE, 否则FALSE 10、输出线性表 Print(L):输出线性表的各个元素 11、其它操作 复制、分解、合并、分类等

第2章--线性表PPT课件

第2章--线性表PPT课件

一个(尾)结点。
.
4
a1,a2,…ai-1都是ai(2≦i≦n)的前驱,其中ai-1是ai的直接 前驱; ai+1,ai+2,…an都是ai(1≦i ≦n-1)的后继,其中ai+1是ai的 直接后继。
2.1.2 线性表的逻辑结构
线性表中的数据元素ai所代表的具体含义随具体应 用的不同而不同,在线性表的定义中,只不过是一个抽 象的表示符号。
以下将对几种主要的操作进行讨论。

1 顺序线性表初始化
Status Init_SqList( SqList *L )
{ L->elem_array=( ElemType * )malloc(MAX_SIZE*sizeof( ElemType ) ) ;
if ( !L -> elem_array ) return ERROR ;
ListInsert ( L, i, &e )
初始条件:线性表L已存在,1≦i≦ListLength(L) ;
操作结果:在线性表L中的第i个位置插入元素e;

.
8
} ADT List
2.2 线性表的顺序存储
2.2.1 线性表的顺序存储结构
顺序存储 :把线性表的结点按逻辑顺序依次存放在 一组地址连续的存储单元里。用这种方法存储的线性表 简称顺序表。
在具体的机器环境下:设线性表的每个元素需占用L 个存储单元,以所占的第一个单元的存储地址作为数据元素 的存储位置。则线性表中第i+1个数据元素的存储位置 LOC(ai+1)和第i个数据元素的存储位置LOC(ai)之间满足 下列关系:
LOC(ai+1)=LOC(ai)+L
线性表的第i个数据元素ai的存储位置为:

大学数据结构课件2.线性表

大学数据结构课件2.线性表

线性表顺序存储结构的主要优缺点
主要优点: 主要优点 算法简单,空间单元利用率高; 算法简单,空间单元利用率高; 主要缺点: 主要缺点 1. 插入和删除时需要移动较多的数据元素,所以在频 插入和删除时需要移动较多的数据元素, 繁时行插入、删除操作时效率较低。 繁时行插入、删除操作时效率较低。 2.需要预先确定数据元素的最大个数。并预先占用一 需要预先确定数据元素的最大个数。 需要预先确定数据元素的最大个数 片地址连续的存储空间。 片地址连续的存储空间。 3. 如果插入数据元素量超过预先分配的存储空间时, 如果插入数据元素量超过预先分配的存储空间时, 要临时扩大有很大困难。 要临时扩大有很大困难。
elem [100] length=0
elem [0]=1 Elem[1]=2 … Elem[4]=5 … Elem[9]=10 length=10
Insert(&myList, i, i+1); Delete(&myList, 4); for(i = 0; i < Length(myList); i++) Get(myList, i, &x); }
程序设计如下: 程序设计如下: void main(void) {Sqlist myList; int i , x; Initiate(&myList); for(i = 0; i < 10; i++)
#include <stdio.h> #include "Sqlist.h" #define MAXSIZE 100 typedef int ElemType;
数据域 指针域

data next
2.3.1 结点结构与指针变量

数据结构 线性表讲解ppt

数据结构  线性表讲解ppt

③ 将该位置后的元素依次向前移动一个位置;
④ 修改当前表的长度;
17
2.2 线性表的顺序表示和实现--顺序表
/*在顺序表中删除第i个元素*/ int ListDelete_sq(SqList &L,int i,ElemType &e){ int k; /*删除位置不合法*/
if(i<1||i>L.length) return ERROR;
a1 a2 a3
……
ai-1
ai L.length L.listsize
10
2.2 线性表的顺序表示和实现--顺序表
3 顺序表的基本操作
顺序表的初始化
为顺序表分配一个预定义大小的一段连续单元, 并将其初始长度设为0。
int InitList_sq(SqList &L) { L.elem=(ElemType *)malloc( LIST_INIT_SIZE*sizeof(ElemType)); if(!L.elem) return ERROR; //初始化失败 L.length=0; //置空表长度为0 L.listsize=LIST_INIT_SIZE; //置初始空间容量 return OK; // 初始化成功,返回1 } //InitList_sq
采用一组任意的存储单元来存放线性表中的数据元 素,这些存储单元可以是连续的,也可以是不连续的。 数据元素间的逻辑关系通过附加信息-指针来描述。 数据元素除了具有代表其本身信息的数据域外,还 有一个用来指示逻辑关系的指针域。这两部分信息组成 数据元素的存储映像,称为结点。
数据域 data 指针域 next
}
O(La_len×Lb_len)
5
2.2 线性表的顺序表示和实现--顺序表

第2章 线性表 (数据结构教程PPT课件)

第2章 线性表 (数据结构教程PPT课件)

3.在数组a中检索(查找)值为X的数据元素
int locate (int a[ ],int n, int x) { int i; i=0; while((i<=n-1)&&(a[i]!=x)) i++; if(i<=n-1) return (i); /*返回的是存储位置*/ else return (0);} }
(2)按值查找即定位 Locate_LinkList(L,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; }
2.2.2 典型操作的算法实现
1. 初始化线性表L
SeqList *init_SeqList( )
{ SeqList *L; L=malloc(sizeof(SeqList)); L->last=-1; return L; }
2.在数组a第i个数据元素之(ai-1)前插入数据 元素X insert (int a[ ],int n,int i, int x) { int j; for(j=n-1;j>=i-1;j--) a[j+1]=a[j]; /* 结点移动 */ a[i-1]=x; /*新元素插入*/ n++; /*修改长度*/ }
4.删除数组a第i个数据元素(ai-1) delete (int a[ ],int n,int i) { int j; for(j=i;j<=n;j++) a[j-1]=a[j]; /* 结点移动 */ n--; /*修改长度*/ }

《第二章线性表》PPT课件

《第二章线性表》PPT课件
en = e; // en为最后一次La插入的值 } // La中不存在和 e 相同的数据元素,则插入
例 2-3
归并两个"其数据元素按值非递减有序 排列"的有序表 LA 和 LB,求得有序表 LC 也具有同样特性.
设 La = <a1, …, ai, …, an>, Lb = <b1, …, bj, …,
ListInsert<Lc, ++k, ai>; ++i; } else { // 将 bj 插入到 Lc 中
ListInsert<Lc, ++k, bj>; ++j; }
void MergeList<List La, List Lb, List &Lc> { // 本算法将非递减的有序表 La 和 Lb 归并为 LcInitList<Lc>; // 构造空的线性表 Lc
是最后一个元素,则用next_e 返回它的后继,否则操作失 败,next_e无定义。
GetElem< L, i, &e >
〔求线性表中某个数据元素〕
初始条件:线性表 L 已存在,
且 1≤i≤LengthList(L)
操作结果:用 e 返回L中第 i 个元素的值。
LocateElem< L, e, compare< > >
bj 插入到 LC 中; 4.重复 2 和 3 两步,直至 LA 或 LB 中元素
被取完为止; 5.将 LA 表或 LB 表中剩余元素复制插入到
LC 表中.
// La 和 Lb 均非空,i = j = 1, k = 0 GetElem<La, i, ai>; GetElem<Lb, j, bj>; if <ai <= bj> { // 将 ai 插入到 Lc 中

最新课件-数据结构教学第2章线性表 精品

最新课件-数据结构教学第2章线性表 精品


在算法 2.1基础上可以进一步分析线性表长度 v.len 的大小 , 如果v.len的值已经等于MAXSIZE-1, 则不允许进行任何插入操
作。 由于C语言函数的一般参数仅能向被调函数传值, 这个值
在返回时也不会改变, 因此在上面的算法中, 采用指针变量p做 参数, 虽然从被调函数返回时p值不变, 但是p中地址所代表的结 构体的内容发生了变化。 struct sequnce v; v=*p;这两个语 句是为了使程序书写简明易懂, 用v来表示结构体。这样, 操作 是在局部变量v结构体上进行, 因此最后还要用 *p=v; 将改变后 的内容赋值给*p, 由指针变量p将结构带回主调函数。
在下面的删除算法中也是同样处理 , 目的是使算法主体部 分简明扼要。处理此类函数的参数传递问题, 上述方法多用了 一个局部变量, 并不理想。在本节最后的源程序例题中, 使用的 是另一种方法, 也不理想。在此, 问题显得如此麻烦, 主要因为C 语言参数传递的限制。 如果换为C++语言, 通过让&v做参数就 可以解决问题。 2. 删除 要删除线性表中的第i个元素ai, 操作和插入操作类似。 把 元素a i+1, …, an分别向前移动一个位置, 使长度为n的线性表 (a1, …, ai-1, ai, …, an),变成长度为n-1的线性表(a1, …, ai-1, ai+1, …, an)。 在下面的算法中, 仍假设a1存放在v.elem [1]之中。 删除算法见算法2.2。算法2.2

i 1
n 1
pi(n-i+1)
假设qi是删除第i个元素的概率 , 则在长度为n的线性 表中删除一个元素时所需移动元素次数的平均次数为
Ede=

数据结构课件-第二章

数据结构课件-第二章

1初始化单链表 Void InitList(LinkList *head) {/* 初始化单链表 */ head=(LinkList)malloc(Sizeof(ListNode)) /*申请头结点空间,并使头指针head指向头结点 */ head->next=NULL; /* 置链尾标记NULL */ }
2.4线性表的链式存储结构

链式存储结构用一组任意的存储单元依次存储 线性表里元素,这组存储单元可以是连续的, 也可以是不连续的,甚至是零散分布在内存的 任何位置上。

为反映出各元素在线性表中的逻辑关系,对每 个数据元素来说,除了存储其本身的信息之外 ,还需存储一个指示其直接后继的信息(即直 接后继的存储位置)。这两部分信息组成一个 数据元素的存储映象,称为结点(Node)。

例如,图2-4-2所示为线性表(dog,pig,cat,fox,hen,bat ,bee,bird)的单链表存储结构,整个链表的存取需从头指针开始 进行,依次顺着每个结点的指针域next找到线性表的各个元素,直 至next域为空为止。

通常我们用箭头表示链域中的指针:
typedef struct Node {ElemType data; /*数据域*/ struct Node *next; /*指针域*/ }ListNode,*LinkList;
2.3.1 线性表的顺序存储

线性表的顺序存储是指用一组地址连续的存储单元依 次存储线性表中的各个元素,使得线性表中在逻辑结 构上相邻的数据元素存储在相邻的存储单元中 。

假设线性表中有n个数据元素,每个数据元素占K个 存储单元,第一个元素a1的存储地址用LOC(a1)表示 ,第i个数据元素ai的地址用LOC(ai)表示,则: 第i个数据元素的地址为: LOC(ai)=LOC(a1)+(i-1)×K (1≤i≤n)

数据结构课件之线性表(ppt 86页)

数据结构课件之线性表(ppt 86页)

删除算法
int DelList(SeqList *L,int i,ElemType *e)
/*在顺序表L中删除第i个数据元素,并用指针参数e返回其值*/
{ int k;
if((i<1)||(i>L->last+1))
{ printf(“删除位置不合法!”); return(ERROR); }
*e= L->elem[i-1]; /* 将删除的元素存放到e所指向的变量中*/
loc(ai) =loc(a1)+(i-1)×k
8
15.10.2019
顺序存储结构示意图
存储地址
Loc(a1) Loc(a1)+(2-1)k

loc(a1)+(i-1)k

loc(a1)+(n-1)k
...
loc(a1)+(maxlen-1)k
内存空间状态
a1 a2

ai

an
9
逻辑地址
1 2

i
操作前提:L为未初始化线性表。 操作结果:将L初始化为空表。 操作前提:线性表L已存在。 操作结果:将L销毁。 操作前提:线性表L已存在 。 操作结果:将表L置为空表。
………
}ADT LinearList
6
15.10.2019
2.2 线性表的顺序存储
2.2.1 线性表的顺序存储结构 2.2.2 线性表顺序存储结构上的基本运算
17
15.10.2019
删除算法示意
将线性表(4,9,15,21,28,30,30,42,51,62)中的第5个元素 删除。
序号
1 2 3 4 5 6 7 8 9 10 4 9 15 21 28 30 30 42 51 62
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

8
2、尾插法建表 头插法建立链表虽然算法简单,但生成的 链表中结点的次序和输入的顺序相反。若希望 二者次序一致,可采用尾插法建表。该方法是 将新结点插入到当前链表的表尾上,为此必须 增加一个尾指针r,使其始终指向当前链表的 尾结点。例:
9
尾插法建立单链表
head ③ s ④


① 建立新节点 ② 向新节点中添入内容 ③ 将新节点链入链尾 ④ 改变尾指针
17
3. 单链表的插入
在链表中插入一个元素的示意图如下: 在链表中插入一个元素的示意图如下: p a b p a x b
p->next 插入步骤(即核心语句): 插入步骤(即核心语句): 1: Step 1:s->next=p->next; 2: Step 2:p->next=s ; 思考:步骤1 能互换么? 思考:步骤1和2能互换么?
// 数据元素的个数
/*结构类型定义好之后,每个变量 结构类型定义好之后, 结构类型定义好之后 的长度就固定了, 求一次即可 求一次即可*/ 的长度就固定了,m求一次即可
3
void build()
//字母链表的生成。要一个一个慢慢链入 字母链表的生成。 字母链表的生成
{ int i; head=(test*)malloc(m); //m=sizeof(test) 前面已求出 p=head; for(i=1;i<26;i++) //因尾结点要特殊处理,故i≠26 { p->data=i+‘a’-1; // 第一个结点值为字符a p->next=(test*)malloc(m); //为后继结点开新空间! 为后继结点开新空间 p=p->next;} //让指针变量P改为指向后继结点 ; p->data=i+‘a’-1; //最后一个元素要单独处理 p->next=NULL ;} //单链表尾结点的指针域要置空! 单链表尾结点的指针域要置空! 单链表尾结点的指针域要置空 新手特别容易忘记!! 新手特别容易忘记!!
16
单链表的修改(或读取) 2. 单链表的修改(或读取)
难点:单链表中想取得第 个元素 个元素, 难点:单链表中想取得第i个元素,必须从头指针出 发寻找(顺藤摸瓜), ),不能随机存取 发寻找(顺藤摸瓜),不能随机存取 。 思路:要修改第 个数据元素 个数据元素, 思路:要修改第i个数据元素,关键是要先找到该结 点的指针p,然后用p->data=new_value 即可。 点的指针 ,然后用 核心语句:见教材P29的GetElem_L函数说明 核心语句:见教材P29的GetElem_L函数说明 Status GetElem_L(LinkList L, int i, ElemType &e) {P=L->next; j=1; while(p&&j<i){p=p->next; ++j;} i if(!p||j>i)return ERROR; e=p->data; return OK;}
sum ++;
//别忘记输出尾结点数据 别忘记输出尾结点数据
讨论:要统计链表中数据元素的个数,该如何改写? 讨论:要统计链表中数据元素的个数,该如何改写?
5
补充: 例:建立单链表
假设线性表中结点的数据类型是字符,我们 逐个输入这些字符型的结点,并以换行符‘\n’ 为输入结束标记。动态地建立单链表的常用方 法有如下两种: 1、头插法建表 该方法从一个空表开始,重复读入数据, 生成新结点,将读入数据存放到新结点的数据 域中,然后将新结点插入到当前链表的表头上, 直到读入结束标志为止。
4
void display()
/*字母链表的输出 字母链表的输出*/ 字母链表的输出
/* 只要没到最后一个元素, 只要没到最后一个元素, 就不停地“顺藤摸瓜” 就不停地“ 顺藤摸瓜” 输出 */
{p=head; while (p->next!=NULL)
{printf("%c",p->data); p=p->next; } printf(“%c\n”,p->data); }
24
显然此算法的时间复杂度也是O(n)。
从上面的讨论可以看出,链表上实现插入 和删除运算,无须移动结点,仅需修改指针。
25
2.3.2 循环链表 循环链表时一种头尾相接的链表。其特点 是无须增加存储量,仅对表的链接方式稍 作改变,即可使得表处理更加方便灵活。 单循环链表:在单链表中,将终端结点的指 针域NULL改为指向表头结点的或开始结 点,就得到了单链形式的循环链表,并简 单称为单循环链表。 为了使空表和非空表的处理一致,循环 链表中也可设置一个头结点。这样,空循 环链表仅有一个自成循环的头结点表示。 如下图所示:
11
说明:第一个生成的结点是开始结点,将开始结 点插入到空表中,是在当前链表的第一个位置 上插入,该位置上的插入操作和链表中其它位 置上的插入操作处理是不一样的,原因是开始 结点的位置是存放在头指针(指针变量)中,
12
如果我们在链表的开始结点之前附加一个结点, 并称它为头结点,那么会带来以下两个优点: a、由于开始结点的位置被存放在头结点的指针 域中,所以在链表的第一个位置上的操作就 和在表的其它位置上的操作一致,无需进行特 殊处理; b、无论链表是否为空,其头指针是指向头结点 在的非空指针(空表中头结点的指针域为空), 因此空表和非空表的处理也就统一了。
10
尾插法建立单链表 linklist *CREATELISTR() { char ch; linklist *head,*s,*r; head=NULL; = r=NULL; = ch=getchar(); = while(ch!=‘$’) { s=malloc(sizeof(linklist)); = s->data=ch; = if (head==NULL) head=s; = else r->next=s; = r=s; = ch=getchar(); = } if (r!=NULL) r->next=NULL; = return head; }
19
具体算法如下: void insertnode(linklist head,datetype x,int i) { listnode * p,*q; p=getnode(head,i-1); if(p==NULL) error(〝position error〞); q=(listnode *)malloc(sizeof(listnode)); q–>data=x; q–>next=p–next; p–>next=q; 20 }
设链表的长度为n,合法的插入位置是1≦i≦n+1。 注意当i=1时,getnode找到的是头结点,当 i=n+1时,getnode找到的是结点an。因此,用i-1 做实参调用getnode时可完成插入位置的合法性 检查。算法的时间主要耗费在查找操作getnode 上,故时间复杂度亦为O(n)。
21
上述算法里动态申请新结点空间时未加错误处理, 可作下列处理: p=(listnode*)malloc(sizeof(listnode)) if(p==NULL) { error(〝No space for node can be obtained〞); return ERROR; } 以上算法的时间复杂度均为O(n)。
22
a i-1的存储位置p。然后令p–>next指向ai的直接 后继结点,即把ai从链上摘下。最后释放结点ai 的空间,将其归还给“存储池”。此过程为:
23
具体算法如下:
void deletelist(linklist head, int i) { listnode * p, *r; p=getnode(head,i-1); if(p= =NULL || p–>next= =NULL) return ERROR; r=p–>next; p–>next=r–>next; free( r ) ; }
13
其算法如下:
linklist createlistr1( ){ char ch; linklist head=(linklist)malloc(sizeof(listnode)); listnode *p,*r
14
r=head; // r 指向链表尾
while((ch=getchar( ))!=‵\n′{ p=(listnode*)malloc(sizeof(listnode)); p–>data=ch; p–>next=p; r=p; } r–>next=NULL; return(head); } 15
2
将全局变量及函数提前说明: 将全局变量及函数提前说明: #include<stdio.h> #include<stdlib.h> typedef struct zzy{char data; struct zzy*next;}test; test *p,*q,*head; int n ; int m=sizeof(test); //一般需要3个指针变量 一般需要3个指针变量
26
head
a1 ⑴ 非空表
….
an
⑵ 空表 在用头指针表示的单链表中,找开始结点a1 的时间是O(1),然而要找到终端结点an,则需 从头指针开始遍历整个链表,其时间是O(n) 27
在很多实际问题中,表的操作常常是在 表的首尾位置上进行,此时头指针表示的 单循环链表就显得不够方便.如果改用尾指 针rear来表示单循环链表,则查找开始结点 a1和终端结点an都很方便,它们的存储位置 分别是(rear–>next) —>next和rear,显然, 查找时间都是O(1)。因此,实际中多采用尾 指针表示单循环链表。 由于循环链表中没有NULL指针,故涉及 遍历操作时,其终止条件就不再像非循环 链表那样判断p或p—>next是否为空,而是 判断它们是否等于某一指定指针,如头指 28 什或尾指针等。
相关文档
最新文档