赞
踩
线性表(Linear List)
是由n(n≥0)个具有相同特性(数据类型)的数据元素(结点)a1,a2,...,ai-1,ai,ai+1,...,an组成的有限序列。
其中,a1为线性起点(起始结点),an为线性终点(终端结点)。对于每一个数据元素ai,我们称ai-1为它的直接前驱,ai+1为它的直接后继。i(1≤i≤n)为下标,是元素的序号,表示元素在表中的位置;n为数据元素总个数,即表长。当n=0时,称线性表为空表。
线性表的存储结构
在计算机中,线性表有两种基本的存储结构:顺序存储结构和链式存储结构。
线性表的顺序表示又称为顺序存储结构或顺序映像。顺序存储,即把逻辑上相邻的数据元素存储在物理上相邻的存储单元中。其特点是依次存储,地址连续——中间没有空出存储单元,且任一元素可随机存取。
线性表的第一个数据元素a1的存储位置,称为线性表的起始位置或基地址。
顺序表中元素存储位置的计算
LOC(ai) = LOC(a1) + (i-1) x m (m为每个元素占用的存储单元)
每个元素的存取时间复杂度为O(1),我们称之为随机存取。
顺序表的表示
1 2 3 4 5 |
|
例如:多项式 Pn(x) = p1xe1 + p2xe2 + ... + pmxem 的顺序存储结构类型定义如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
|
顺序表初始化、销毁顺序表、清空顺序表、求顺序表长度、判断顺序表是否为空及顺序表的取值等操作,它们的时间复杂度都为O(1)
1 2 3 4 5 6 7 8 |
|
平均查找长度ASL(Average Search Length):为确定记录在表中的位置,需要与给定值进行比较的关键字的个数的期望值叫做查找算法的平均查找长度。
含有n个记录的表,查找成功时:
ASL = 1/n * (1+2+...+n) = (n+1)/2
所以,顺序表查找算法的平均时间复杂度为:O(n)
【算法思路】
【代码】
1 2 3 4 5 6 7 8 9 10 11 |
|
【算法分析】
算法时间主要耗费在移动元素的操作上。
若插入在尾结点之后,则需要移动0次;若插入在首结点之前,则需要移动n次;在各个位置插入(共n+1种可能)的平均移动次数为:E = 1/(n+1) * (0+1+...+n) = n/2
所以,顺序表插入算法的平均时间复杂度为:O(n)
【算法思路】
【代码】
1 2 3 4 5 6 7 8 |
|
【算法分析】
算法时间主要耗费在移动元素的操作上。
若删除尾结点,则需要移动0次;若删除首结点,则需要移动n-1次;在各个位置删除(共n种可能)的平均移动次数为:E = 1/n * (0+1+...+n-1) = (n-1)/2
所以,顺序表删除算法的平均时间复杂度为:O(n)
由于没有占用辅助空间,顺序表所有操作的空间复杂度都为:O(1)
优点:
缺点:
链式存储结构又称为非顺序映像或链式映像。其特点是:
链式存储相关术语:
Q1:如何表示空表?
Q2:在链表中附设头结点有什么好处?
Q3:头结点的数据域内装的是什么?
头结点的数据域可以为空,也可以存放线性表长度等附加信息,但此结点不能计入链表长度值。
单链表是由表头唯一确定,因此单链表可以用头指针的名字来命名。若头指针名为L,则把链表称为表L。
单链表的存储结构
1 2 3 4 5 |
|
定义链表和节点指针可以用 LinkList L; 或LNode* L;
这两种方式等价,但为了表述清晰,一般建议使用LinkList定义链表,Lnode定义结点指针。即:
定义链表:LinkList L;
定义节点指针:Lnode* p;
3.1.1 单链表的初始化(带头结点)
即构造一个如图的空表:
【算法思路】
【代码】
1 2 3 4 5 6 |
|
3.1.2 判断单链表是否为空
【算法思路】
判断头结点指针域是否为空。
【代码】
1 2 3 4 5 6 |
|
3.1.3 单链表的销毁
【算法思路】
从头指针开始,依次释放所有节点。
【代码】
1 2 3 4 5 6 7 8 9 10 |
|
3.1.4 清空单链表
【算法思路】
从首元结点开始,依次释放所有结点,并将头结点指针域设置为空。
【代码】
1 2 3 4 5 6 7 8 9 10 11 |
|
3.1.5 求单链表的表长
【算法思路】
从首元结点开始,依次计数所有结点。
【代码】
1 2 3 4 5 6 7 8 9 10 11 |
|
3.1.6 取值
【算法思路】
从链表的头指针出发,顺着链域next逐个结点往下搜索,直至搜索到第i个结点位置。我们称之为顺序存取。
【代码】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
3.1.7 查找
【算法思路】
【代码】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
【算法分析】
因线性链表只能顺序存取,即在查找时要从头指针找起,因此查找的时间复杂度为:O(n)
3.1.8 插入新结点
【算法思路】
【代码】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
【算法分析】
在编译 p->next = s 这句代码是会报异常:“不能将Lnode*类型的值分配到Lnode类型的实体”。
因线性链表不需要移动元素,只要修改指针,一般情况下插入操作的时间复杂度为:O(1)。但是,如果要在单链表中进行前插操作,由于要从头查找前驱结点,其时间复杂度为:O(n)。
3.1.9 删除结点
【算法思路】
【代码】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
【算法分析】
其时间复杂度和插入操作一致。
3.1.10 建立单链表
(1)头插法——元素插入在链表头部,也叫前插法。
【算法思路】
【代码】
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
(2)尾插法——元素插入在链表尾部,也叫后插法。
【算法思路】
【代码】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
【算法分析】
建立单链表时间复杂度为:O(n)
双向链表:在单链表的每个结点里再增加一个指向其直接前驱的指针域prior,这样链中就形成了两个方向不同的链,故称为双向链表。
双向循环链表:让头结点的前驱指针指向链表的最后一个结点;让最后一个节点的后继指针指向头结点。
双向链表的结构定义
1 2 3 4 5 |
|
双向链表结构具有对称性(设指针p指向某一结点):
p -> prior -> next = p = p ->next -> prior
在双向链表中有些操作(求表长、取值等),因仅涉及一个方向的指针,所以他们的算法与线性链表相同。但在插入、删除时,则需要同时修改两个方向上的指针,两者的时间复杂度都为O(n)。
3.2.1 双向链表的插入
【算法思路】
【代码】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
3.2.2 双向链表的删除
【算法思路】
【代码】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
|
循环链表是一种头尾相接的链表,表中最后一个结点的指针域指向头结点,整个链表形成一个环。
优点:从表中任一结点出发均可找到表中其他结点。
示例:带尾指针循环链表的合并(将Tb合并在Ta之后)
【算法思路】
【代码】
1 2 3 4 5 6 7 8 9 |
|
存储密度定义:
存储密度 = 结点数据本身占用的空间 / 结点占用的空间总量
比如单链表某个节点p,其数据域占8个字节,指针域占4个字节,其存储密度 = 8/12 = 67%。
已知线性表La和Lb中的数据元素按值非递减有序排列,现要求将La和Lb归并为一个新的线性表Lc,且Lc中的数据元素仍按值非递减有序排列。
例如:La=(1,7,8) Lb=(2,4,6,8,10,11) → Lc=(1,2,4,6,7,8,8,10,11)
(1)顺序表实现有序表合并
【算法思路】
【代码】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
【算法分析】
时间复杂度:O(ListLength(La) + ListLength(Lb))
空间复杂度:O(ListLength(La) + ListLength(Lb))
(2)链表实现有序表合并
【算法思路】
【代码】
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
【算法分析】
时间复杂度:O(ListLength(La) + ListLength(Lb))
空间复杂度:O(1)
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。