线性表的应用
2.7.1 线性表的合并
【例2.1】求解一般集合的并集问题。
【问题描述】
已知两个集合A和B现要求一个新的集合A=A∪B。例如,设
A=(7,5,3,11)
B=(2,6,3)
那么合并后为:
A=(7,5,3,11,2,6)
【问题分析】
可以利用两个线性表LA和LB分别表示集合A和集合B(即线性表中的数据元素为集合中的成员),这样只需扩大线性表LA,将存在于LB而不存在于LA中的数据元素插入到LA之中去。只要从LB中依次取得每个数据元素,并依值在LA中进行查访,若不存在,则插入之。
上述操作过程可用算法2.15来描述,具体实现既可采用顺序形式,也可采用链式形式。
算法2.15 线性表的合并
【算法步骤】
(1)、分别获取LA表长m和LB表长n。
(2)、从LB中的第1个数据元素开始,循环n次执行以下操作:
1、从LB中查找第i(1<=i<=n)个数据元素赋给e;
2、在LA中查找元素e,如果不存在,则将e插在表LA之后。
【算法描述】
void MergeList(List &LA,List &LB)
{
//将所有在线性表LB中不在线性表LA中的数据元素插入到LA中
m=ListLength(LA);
n=ListLength(LB); //求线性表的长度
for(i=1;i<=n;i++)
{
GetElem(LB,i,e); //取LB第i个数据元素赋值给e
if(!LocateElem(LA,e)) //LA中不存在与e相等的数据元素
ListInsert(LA,++m,e);
}
}
【算法分析】
上述算法的时间复杂度取决于抽象数据类型List定义中基本操作的执行时间,假设LA和LB中的表长分别为m和n,循执行n次,则:
当采用顺序存储结构时,在每次循换中,GetElem与ListInsert这两个操作的执行时间和表长无关,LocateElem的执行时间和表长m成正比,因此,算法
的时间复杂度为O(m×n)。
当采用链式存储结构时,在每次循换中,GetElem的执行时间和表长n成正比,而LocateElem和ListInsert这两个操作的执行时间和表长m成正比,因此,若假设m大于n,算法2.15的时间复杂度也为O(m×n)。
2.7.2 有序表的合并
若线性表中的数据元素之间可以互相比较,并且数据元素在线性表中依值非递减或非递增有序排列,则称该线性表为有序表(Ordered List)。
【例2.2】求解有序集合的并集问题。
【问题描述】
有序集合是指集合中的元素的有序排列。已知两个有序集合A和B,数据元素按值非递减有序排列,现要求一个新的集合C=A∪B,使得集合C中的元素仍然按值非递减有序排列。
例如,设
A=(3,5,8,11)
B=(2,6,8,9,11,15,20)
则
C=(2,3,5,6,8,9,11,11,15,20)
【问题分析】
与上述例2.1一样,可以利用两个线性表LA和LB分别表示集合A和集合B,不同的是,此例中的LA和LB有序,这样便没有必要从LB中依次取得每个数据元素,到LA中进行查访。
如果LA和LB两个表长分别记作m和n,则合并后的新表的表长应该为m+n。
由于LC中的数据元素或是LA中的元素,或是LB中的数据元素,因此只要先设LC为空表,然后将LA和LB中的数据元素依次逐个插入到LC中即可。为使LC中的元素按值非递减有序排列,可设两个指针pa和pb分别指向LA和LB中的某个元素,若设pa当前所指的元素为a,pb当前所指的元素为b,则当前应插入到LC中的元素c为{a 当a<=b时 或 b 当a>b时 }
显然,指针pa和pb的初值分别指向两个有序表的第一个元素,在所指元素插入LC之后,在LA和LB中顺序后移。
根据上述分析,分别给出有序表的顺序存储结构和链式存储结构相应合并算法实现。
算法2.16 顺序有序表的合并
【算法步骤】
- 创建一个表长为m+n的空表LC
- 指针pc初始化,指向LC的第一个元素
- 指针pa和pb初始化,分别指向LA和LB的第一个元素
- 当指针pa和pb均未到达相应表尾的时候,则依次比较pa和pb所指的元素值,从LA或LB中“摘取”元素值较小的结点插入到LC的最后
- 如果pb已经到达LB的表尾,依次将LA的剩余元素插入到LC的最后
- 如果pb已经到达LA的表尾,依次将LB的剩余元素插入到LC的最后
【算法描述】
void MergeList_Sq(SqList LA,SqList LB,SqList LC)
{
//已知顺序有序表LA和LB的数据元素按值非递减排列
//那么归并LA和LB之后得到的新的顺序表LC也按值非递减顺序排列
LC.length=LA.length+LB.length;//新表长度合并为两表的长度之和
LC.length=new ElemType[LC.length]<