You are on page 1of 28

上节回顾

( 1 )顺序表的定义
typedef struct {
datatype data[maxsize]; // 顺序表数据域
int n; // 顺序表长度
} sqlist;

 datatype 是顺序表内元素的类型,可通过 typedef 具


体指定
 maxsize 是顺序表容量,即顺序表最大长度
 n 是顺序表长度,即元素个数
 sqlist 是顺序表类型,可用于定义变量或指针
sqlist a, *p;
上节回顾
( 2 )顺序表的插入运算
Insert(L,i,x) 表示在顺序表 L 的第 i 个元素前插入数
据x
① 检查顺序表是否已满
② 移动数据,最后一个元素开始往前至第 i 个元素,
将每个元素后移一位

…… a[i] a[i+1]
A …… 16 9
上节回顾
( 2 )顺序表的插入运算
Insert(L,i,x) 表示在顺序表 L 的第 i 个元素前插入数
据x
① 检查顺序表是否已满
② 移动数据,最后一个元素开始往前至第 i 个元素,
将每个元素后移一位
③ 插入数据

…… a[i] a[i+1] a[i+2]


A …… 16 16 9
上节回顾
( 2 )顺序表的插入运算
Insert(L,i,x) 表示在顺序表 L 的第 i 个元素前插入数
据x
① 检查顺序表是否已满
② 移动数据,最后一个元素开始往前至第 i 个元素,
将每个元素后移一位
③ 插入数据
④ 表长加 1
…… a[i] a[i+1] a[i+2]
A …… x 16 9
上节回顾
( 2 )顺序表的插入运算

时间复杂度:

 最好——插入位置在表尾,不用移动数据, O(1)

 最坏——插入位置在表头,移动 n 个数据, O(n)

 平均, O(n)
上节回顾
( 3 )顺序表的删除运算
Delete(L,i) 表示把顺序表 L 的第 i 个元素删除
① 检测表是否为空
② 移动数据,从第 i 个元素开始,将每个元素前移一

…… a[i] a[i+1] a[i+2]


A …… 16 9 20
上节回顾
( 3 )顺序表的删除运算
Delete(L,i) 表示把顺序表 L 的第 i 个元素删除
① 检测表是否为空
② 移动数据,从第 i 个元素开始,将每个元素前移一

…… a[i] a[i+1] a[i+2]


A …… 9 20 20
上节回顾
( 3 )顺序表的删除运算
Delete(L,i) 表示把顺序表 L 的第 i 个元素删除
① 检测表是否为空
② 移动数据,从第 i 个元素开始,将每个元素前移一

③ 表长减 1

…… a[i] a[i+1] a[i+2]


A …… 9 20
上节回顾
( 3 )顺序表的删除运算

时间复杂度:

 最好——删除位置在表尾,不用移动数据, O(1)

 最坏——删除位置在表头,移动 n-1 个数据, O(n)

 平均, O(n)
上节回顾
( 4 )顺序表的查找运算
Locate(L,x) 表示寻找顺序表 L 中值为 x 的元素位置
for 顺序表中每一个元素 ai
if ai == k return i;
return 0;

时间复杂度:
最好——待查数据在表头,只比较一次, O(1)
最坏——待查数据在表尾 / 不存在,比较 n/n+1 个数据
, O(n)
平均, O(n)
课堂练习

( 1 )顺序表的优点是( )
A. 插入方便 B. 删除方便
C. 随机读取方便 D. 节省空间

答案: C
课堂练习
( 2 )下面应用,不适合采用顺序表的是( )
A. 逆转线性表内的元素
B. 求线性表奇数位置上的元素之和
C. 快速排序中的划分操作
D. 字符串中的替换操作

答案: D
分析:
A ,前后元素交换; B ,随机读取奇数位置的元素; C
,交替扫描; D ,考虑到待替换和被替换的字符串长短
不同,可能需要频繁地前移或后移数据
课堂练习
( 3 )在一个长度为 n (n≥ 1) 的顺序表中的第 i 个元
素之前插入一个元素时,需要向后移动( )个元素。

( 4 )在一个长度为 n (n≥ 1) 的顺序表中删除第 i 个


元素时,最多需要向前移动( )个元素。

答案:
( 3 ) n-i+1 ,即从 i 到 n 之间的元素个数
( 4 ) n-1 ,当被删元素位于表头,则数据移动个数最
多,需移动 n-1 个
第 4 讲 链表
2.3 线性表的链接实现
顺序表的问题:
( 1 )插入、删除数据需要移动大量的数据
( 2 )需要预分配大量的空间

解决方法:
用一组任意的存储单元来存放线性表的结点,结点之间
的逻辑关系用指针(内存地址)来描述
( 1 )插入和删除结点时,只需要修改指针指向,不需
要移动数据在内存的位置
( 2 )可实现动态分配空间,需要时才生成结点
链表
2.3 线性表的链接实现
 链表:采用链接存储结构的线性表,链表中的数据元素用
结点来描述,用指针来链接

head ……
 结点:是一个结构体类型,包括两个域——数据域和指针
域 数据域 指针域 指针域 数据域 指针域

( 1 )数据域,存放结点的数据,可以包含多种类型的数据
( 2 )指针域,记录相邻结点的地址(不连续),体现当前
结点与相邻结点的逻辑关系
2.3 线性表的链接实现
 链表的主要分类:
单链表 循环链表
• 每个结点只有一个指针域
• 每个结点只有一个指针域
• 尾部结点与首结点相连

head ˄
head

双链表 静态链表

• 每个结点有两个指针域,分别与 • 用数组下标代替指针
前趋和后继结点相连

next next ˄ 3 9 8 7 2 6 10 5 4
head
˄ front front a b c d e f g h i
2.3.1 单链表
 最常见的链表,其结点只有一个指针域,用于指向后
继结点

1000 1350 1230


head ……

头指针
• 指向单链表的首结点
• 单链表的入口 data next
• 作为单链表名称
结点
空表时, head=NULL head NULL
2.3.1 单链表
 带头结点的单链表,即在单链表首结点前设置的一个
特殊的结点
表结点
head
× D D D ……

头结点
• 数据域不用(或用于记录链表 统一空表与非
元素个数) 空表的操作
• 指针域指向单链表首结点

空表时, head->next=NULL head × ∧


2.3.1 单链表 区别于 typedef struct node pointer
 定义
typedef struct node * pointer①; // 结点指针类型
struct node② { // 结点结构
datatype data; // 数据域
pointer next; // 指针域
};
typedef pointer lklist③; // 单链表类型,即头指针类型
① pointer 类型
typedef 将 pointer 重命名为 struct node * ,是结
构体 struct node 的指针类型。
pointer next;  struct node * next;
2.3.1 单链表
 定义
typedef struct node * pointer①; // 结点指针类型
struct node② { // 结点结构
datatype data; // 数据域
pointer next; // 指针域
};
typedef pointer lklist③; // 单链表类型,即头指针类型
② struct node 结构体
单链表的核心构成。包括两个域:数据域和指针域
( 1 )数据域 data ,类型为 datatype ,可通过 type
def 来具体指定 datatype
( 2 )指针域 next ,类型为 pointer ,即结点指针类
型,用于指向后继结点
2.3.1 单链表
 定义
typedef struct node * pointer①; // 结点指针类型
struct node② { // 结点结构
datatype data; // 数据域
pointer next; // 指针域
};
typedef pointer lklist③; // 单链表类型,即头指针类型
③ lklist 类型
lklist(link list) ,与 pointer 类型相同,即结构
体 struct node * 类型。
有 pointer 了,为什么还
要再弄一个 lklist??
2.3.1 单链表
 定义
typedef struct node * pointer①; // 结点指针类型
struct node② { // 结点结构
datatype data; // 数据域
pointer next; // 指针域
};
typedef pointer lklist③; // 单链表类型,即头指针类型
③ lklist 类型
lklist(link list) ,与 pointer 类型相同,即结构
体 struct node * 类型。
lklist 专门用于定义单链表; pointer 专门用于定义
结点。实质上两者相同,只是语义上有所区别。
lklist A; // 单链表头指针 pointer A; // 单链表结点
怎么动态创建二维数组?
2.3.1 单链表
结点的动态定义,访问和释放
( 1 )动态定义,即需要时从内存中申请空间
C 语言版(利用 malloc 函数)

pointer p1 = (pointer) malloc(sizeof(struct node));

pointer p2 = (pointer) malloc(n*sizeof(struct node));


2.3.1 单链表
结点的动态定义,访问和释放
( 1 )动态定义,即需要时从内存中申请空间
C 语言版(利用 malloc 函数)
pointer p1 = (pointer) malloc(sizeof(struct node));

pointer p2 = (pointer) malloc(n*sizeof(struct node));

// 先创建二维数组
int** p3 = (int**) malloc(m*n*sizeof(int));
// 再循环指定每一行的空间大小
for(int i=0;i<m;i++)
p3[i] = (int*) malloc(n*sizeof(int));
2.3.1 单链表
结点的动态定义,访问和释放
( 1 )动态定义,即需要时从内存中申请空间
C++ 版(利用关键字 new )

pointer p1 = new node; // 不用 struct ,不能用 pointer

pointer p2 = new node[n]; // 可以用变量指定数组长度

注意,用 new 创建的返回值是指针类型


2.3.1 单链表
结点的动态定义,访问和释放
( 2 )结点的访问
与结构体的访问类似
pointer p = new node; // 注意,创建后要让其指向结点

(*p).data = 10;
// 先通过 * 运算符获取 p 指向的结点,再通过 . 运算符访
问域

pnext = NULL;
// 通过运算符直指通过指针访问结点域
2.3.1 单链表
 结点的动态定义,访问和释放
( 3 )结点的释放( delete )
删除结点后,结点所占的空间要释放处理,防止内存资
源浪费
 释放单个结点

pointer p = new node;


delete p;

 释放一个结点数组

pointer p = new node[n];


delete []p;

You might also like