2.6、线性表的应用
2.6.1、线性表的合并
问题描述:
- 已知两个集合A和B,现要求一个新的集合
A
=
A
∪
B
A=A∪B
A=A∪B。例如,设
A
=
(
7
,
5
,
3
,
11
)
A = (7, 5, 3, 11)
A=(7,5,3,11)和
B
=
(
2
,
6
,
3
)
B = (2, 6, 3)
B=(2,6,3)合并后
A
=
(
7
,
5
,
3
,
11
,
2
,
6
)
A = (7, 5, 3, 11, 2, 6)
A=(7,5,3,11,2,6)
算法步骤:
- 分别获取La表长m和Lb表长n
- 从Lb中第一个元素开始,循环n次执行以下操作:
- 从Lb中查找第i(1 <= i <= n)个数据元素赋给e
- 在La中查找元素e,如果不存在,则将e插在表La的最后
线性表的合并
void MergeList(List &La, List Lb) {
// 将所有在线性表Lb但不在La中的数据元素插入到La中
m = ListLength(La); n = ListLength(Lb); // 求线性表的长度
for (i = 0; i <= n; i++) {
GetElem(Lb, i, e); // 取Lb中第i个数据元素赋给e
if (!LocateElem(La, e)); // La中不存在和e相同的数据元素
ListInsert(La, ++m, e); // 将e插在La的最后
}
}
C语言实现:
2.6.2、顺序有序表的合并
问题描述:
- 已知线性表La和Lb中的元素按值非递减有序排列,现要求将La和Lb归并为一个新的线性表Lc,且Lc中的数据元素仍按值非递减有序排列
L
a
=
(
1
,
7
,
8
)
La = (1, 7, 8)
La=(1,7,8)和
L
b
=
(
2
,
4
,
6
,
8
,
10
,
11
)
Lb = (2, 4, 6, 8, 10, 11)
Lb=(2,4,6,8,10,11)合并后为
L
c
=
(
1
,
2
,
4
,
6
,
7
,
8
,
8
,
10
,
11
)
Lc = (1, 2, 4, 6, 7, 8, 8, 10, 11)
Lc=(1,2,4,6,7,8,8,10,11)
算法步骤:
- 创建一个表长为m + n的空表LC
- 指针pc初始化,指向LC的第一个元素
- 指针pa和pb初始化,分别指向LA和LB的第一个元素
- 当指针pa和pb均未到达相应表尾时,则依次比较pa和pb所指向的元素值,从LA或LB中摘取元素值较小的结点插入到LC的最后
- 如果pb已达到LB的表尾,依次将LA的剩余元素插入LC的最后
- 如果pa已到达LA的表尾,依次将LB的剩余元素插入LC的最后
算法描述:
void MergeList_Sq(SqList LA, SqList LB, SqList LC)
{ // 已知顺序表LA和LB的元素按值非递减排列
// 归并LA和LB得到新的顺序有序表LC,LC的元素也按值非递减排列
LC.length = LA.length + LB.length; // 先表长为待合并两表的长度之和
LC.elem = new ELemType[LC.length]; // 为合并后的新表分配一个数组空间
pc = LC.elem; // 指针pc指向新表的第一个元素
pa = LA.elem; pb = LB.elem; // 指针pa和pb的初值分别指向两个表的第一个元素
pa_last = LA.elem + LA.length - 1; // 指针pa_last指向LA的最后一个元素
pb_last = LB.elem + LB.length - 1; // 指针pb_last指向LB的最后一个元素
while ((pa <= pa_last) &&(pb <= pb_last)) // LA和LB均未到达表尾
{
if (*pa <= *pb) *pc++ = *pa++; // 依次摘取两个表中值较小的结点插入到LC的最后
else *pc++ = *pb++;
}
while (pa <= pa_last) *pc++ = *pa++; // LB已到达表尾,依次将LA的剩余元素插入到LC的最后
while (pb <= pb_last) *pc++ = *pb++; // LA已到达表尾,依次将LB的剩余元素插入到LC的最后
}
复杂度分析:
- 时间复杂度:
O
(
L
i
s
t
L
e
n
g
t
h
(
L
a
)
+
L
i
s
t
L
e
n
g
t
h
(
L
b
)
)
O(ListLength(La) + ListLength(Lb))
O(ListLength(La)+ListLength(Lb))
- 空间复杂度:
O
(
L
i
s
t
L
e
n
g
t
h
(
L
a
)
+
L
i
s
t
L
e
n
g
t
h
(
L
b
)
)
O(ListLength(La) + ListLength(Lb))
O(ListLength(La)+ListLength(Lb))
2.6.3、链表有序表的合并
问题描述:
- 已知线性表La和Lb中的元素按值非递减有序排列,现要求将La和Lb归并为一个新的线性表Lc,且Lc中的数据元素仍按值非递减有序排列
L
a
=
(
1
,
7
,
8
)
La = (1, 7, 8)
La=(1,7,8)和
L
b
=
(
2
,
4
,
6
,
8
,
10
,
11
)
Lb = (2, 4, 6, 8, 10, 11)
Lb=(2,4,6,8,10,11)合并后为
L
c
=
(
1
,
2
,
4
,
6
,
7
,
8
,
8
,
10
,
11
)
Lc = (1, 2, 4, 6, 7, 8, 8, 10, 11)
Lc=(1,2,4,6,7,8,8,10,11)
算法步骤:
- 指针pa和pb初始化,分别指向LA和LB的第一个结点
- LC的结点取值为LA的头结点
- 指针pc初始化,指向LC的头结点
- 当指针pa和pb均未到达相应表尾时,则依次比较pa和pb所指的元素值,从LA或LB中摘取元素值比较小的结点插入到LC的最后
- 将非空列表的剩余段插入到pc所指结点之后
- 释放LB的头结点
算法描述:
void MergeList_L(LinkList &LA, LinkList &LB, LinkLIst &LC)
{ // 已知单链表LA和LB的元素按值非递减排列
// 归并LA和LB得到新的单链表LC,LC的元素也按值非递减排列
pa = LA->next;pb = LB->next; // pa和pb的初值分别指向两个表的第一个结点
LC = LA; // 用LA的头结点作为LC的头结点
pc = LC; // pc的初值指向LC的头结点
while(pa && pb)
{ // LA和LB均为到达表尾,依次摘取两表中较小的结点插入到LC的最后
if (pa->data <= pb->data) // 摘取pa所指结点
{
pc->next = pa; // 将pa所指结点链接到pc所指结点之后
pc = pa; // pc指向pa
pa = pa->next; // pa指向下一个结点
}
else // 摘取pb所指结点
{
pc->next = pb; // 将pb所指结点链接到pc所指结点之后
pc = pb; // pc指向pb
pb = pb->next; // pb指向下一个结点
}
} // while
pc->next = pa ? pa : pb; // 将非空表的剩余段插入到pc所指结点之后
delete LB; // 释放LB的头结点
}
复杂度分析:
- 时间复杂度:
O
(
L
i
s
t
L
e
n
g
t
h
(
L
a
)
+
L
i
s
t
L
e
n
g
t
h
(
L
b
)
)
O(ListLength(La) + ListLength(Lb))
O(ListLength(La)+ListLength(Lb))
- 空间复杂度:
O
(
L
i
s
t
L
e
n
g
t
h
(
L
a
)
+
L
i
s
t
L
e
n
g
t
h
(
L
b
)
)
O(ListLength(La) + ListLength(Lb))
O(ListLength(La)+ListLength(Lb))