[数据结构]线性表合并

本文介绍了线性表合并问题,包括两种合并方式:一种是顺序表示,通过比较LA和LB的最小元素进行合并;另一种是链式表示,将LB中的元素插入LA中。详细讲解了数据结构线性表的链式和顺序表示,并提供了c++源代码实现。
摘要由CSDN通过智能技术生成

一、问题描述

线性表合并是程序设计语言编译中的一个最基本的问题,现在有两个线性表LA和LB,其中的元素都是按照非递减有序排列的,要将两个LA和LB归并为一个新的线性表LC,使得LC中的元素仍然是非递减有序的。

本实验的合并方式有两种。第一种是分别取LA和LB的第一个元素,即各自的最小的元素进行比较,选择较小的元素加入LC尾部,然后重复以上步骤;当LA表空了或者LB表空了的时候,将另一个表剩下的元素按照顺序加入LC的尾部,从而保证LC中元素有序。第二种方式是以LA为母表,将LB中的元素向LA中插入,直到LB表空,得到的新的LA表就是最终需要的LC表。

本实验采用线性表实现,采用了链式表示和顺序表示两种实现方式。根据各自的特点,链式表示对应了第二种合并方式,而顺序表示对应了第一种合并方式。

二、数据结构——线性表

1、链式表示:

链式表示的特点是用一组任意的存储单元存储线性表的数据元素,每个元素包括两个域——数据域和指针域。其中数据域是存储数据信息的域,本实验中默认所处理的数据元素都是在整型(int)范围内的数据;指针域中存储一个指针,指向当前元素的下一个元素的地址。n个结点按照如上关系连接起来,形成一个链表,就是线性表的链式表示。

由于链式表示对于数据的插入、删除操作比较方便,而查找一个元素的效率比较低下,于是选择用第二种合并方式,即以LA为母表,将LB中的元素一个一个插入LA中。

首先,每个结点的是一个node型的变量,包含一个int型变量Num和一个node*型的指针变量next。正如上文所描述,Num保存该结点的数值,next保存逻辑上下一个结点的地址。然后定义了一个名叫MyList的类,其中有private型的变量包含线性表自身的基本变量,比如元素个数、首地址等等;还包括public型的线性表的基本操作函数,比如初始化(InitList)、清除(ClearList)、打印(PrintList)等等。

2、顺序表示:

顺序表示是指的用一段地址连续的区域存储一个线性表,用物理存储位置的连续表示线性表的顺序关系。这就要求元素之间维持严格的物理位置关系,在访问变得简单的同时,对线性表的修改操作给线性表的维护带来了很大的麻烦。

由于顺序表示对于数据的操作比较方便,而对线性表的数据进行操作比较麻烦且效率低下,故选择第一种合并方式,即将LA和LB合并到一个新的线性表LC中。

首先,申请一段连续的空间,当空间不够时申请一个更大的空间,再把之前的数据搬过去。基本功能与链式表示基本相同,实现上略有差别。

三、算法的设计和实现

1、第一种合并方式

(1)建立线性表LA和LB,并读入数据。

(2)建立空线性表LC。

(3)分别选取LA中未读过的最小的元素和LB中未读过的最小的元素,进行比较,将较小的元素加入新的线性表LC中,较大元素视作未读过的元素。

(4)重复步骤(2)直到LA或者LB的元素都被读过了。若LA中的元素都被度过了,则将LB中剩下未读的元素按顺序依次添加到LC的尾部;否则,将LA中的剩下未读的元素按顺序依次添加到LC的尾部。

(5)得到的LC就是最终结果。

2、第二种合并方式

(1)建立线性表LA和LB,并读入数据。

(2)用aIndex标记LA中读到元素的位置,将其位置的元素与LB中第一个元素进行比较。

(3)若LA中当前元素较小,则aIndex向后移,重复(2)直到LB为空或者LA到末端;否则将LB中的第一个元素插入LA的当前位置,aIndex向后移,删除LB中的第一个元素,重复(2)直到LB为空或者LA到末端。

(4)若LB为空,则LA已经是最终结果;否则,将LB剩下的元素按顺序依次加入LA的末端,得到最终结果。

四、预期结果和实验中的问题

1、预期结果是程序可以正确地合成两个线性表LA和LB,如LA={1,1,2},LB={1,2,2,3},则得到的结果应该是{1,1,1,2,2,2,3}。

2、实际运行中曾遇到的问题:

(1)使用顺序结构表示线性表的时候,可能会出现初始申请的空间不够的情况,需要额外申请一个更大的空间,把之前的元素全部复制过去,然后把之前的空间释放掉。

(2)由于链式表示和顺序表示各有特点,在MyList类中的函数有些细节不一样,比如有两个函数,分别是PriorElem(e,&Pre_e):若e是L中的元素,则返回e的前躯,以及NextElem(e,&Next_e):若e是L中的元素,则返回e的后继。由于顺序表示的访问上的便利,我多写了一个函数ElemPos(e,&Pos):若e是L中的元素,则返回e的位置。借助这个函数,之前两个函数的实现简单了许多。而这对于链式表示是没有太大的必要的。

(3)我第一次写顺序表示的链表时,我的合并函数是每合并一个元素,则将其从原表中删去。而顺序表示在删除数据上的笨拙之处立刻显现出来,时间复杂度变到了O(n^2),这是非常不明智的。修改之后的实现时间复杂度为O(n)。下面是修改前的合并函数:

 1 void MergeList(MyList La, MyList Lb, MyList &Lc)
 2 {
 3     int aElem, bElem, cLen = 0;
 4     Lc.InitList();
 5     while((!La.ListEmpty()) && (!Lb.ListEmpty()))
 6     {
 7         La.GetElem(1, aElem);
 8         Lb.GetElem(1, bElem);
 9         if(aElem <= bElem)
10         {
11             Lc.ListInsert(++cLen, aElem);
12             La.ListDelete(1, aElem);
13         }
14         else
15         {
16             Lc.ListInsert(++cLen, bElem);
17             Lb.ListDelete(1, bElem);
18         }
19     }
20     while(!La.ListEmpty())
21     {
22         La.ListDelete(1, aElem);
23         Lc.ListInsert(++cLen, aElem);
24     }
25     while(!Lb.ListEmpty())
26     {
27         Lb.ListDelete(1, bElem);
28         Lc.ListInsert(++cLen, bElem);
29     }
30 }

附:c++源代码:

1、第一种合并方式,顺序表示

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <new>
  4 
  5 using namespace std;
  6 
  7 #define LIST_INIT_SIZE 100 //线性表存储空间的初始分配量
  8 #define LISTINCREMENT 10 //线性表存储空间的分配增量
  9 
 10 class MyList
 11 {
 12 private:
 13     int *Elem; //存储空间基址
 14     int Len; //当前元素个数
 15     int ListSize; //当前分配的储存容量
 16 
 17 public:
 18     void InitList() //构造一个空的线性表
 19     {
 20         Elem = new int(LIST_INIT_SIZE);
 21         Len = 0;
 22         ListSize = LIST_INIT_SIZE;
 23     }
 24     void ClearList() //重置为空表
 25     {
 26         delete Elem;
 27         Len = 0;
 28     }
 29     bool ListEmpty() //判断L是否为空表
 30     {
 31         return Len == 0;
 32     }
 33     int ListLength() //返回L中数据元素个数
 34     {
 35         return Len;
 36     }
 37     bool GetElem(int Pos, int &RetElem) //返回第Pos个元素,出错返回true
 38     {
 39         if(Pos < 1 || Pos > Len)
 40         {
 41             printf("Wrong position!\n");
 42             return true;
 43         }
 44         RetElem = Elem[Pos - 1];
 45         return false
### 回答1: 归并两个有序表la和lb一个新的有序表lc,就是将la和lb中的元素按照非递减的顺序合并到lc中。具体操作是,从la和lb中分别取出最小的元素进行比较,将较小的元素放入lc中,并将该元素所在的表的指针向后移动一位,直到la和lb中的元素全部放入lc中。最终得到的lc也是一个非递减有序的表。 ### 回答2: 首先,我们需要了解“归并排序”的基本思想:将一个序列分两部分,对两部分分别进行排序,然后将两个有序的子序列合并一个有序序列。对于两个有序表la和lb,即为我们要将它们合并一个新的有序表lc。 具体实现过程如下: 1. 定义指向待合并序列la和lb的指针i和j,以及指向新序列lc的指针k。 2. 比较la[i]和lb[j]的大小关系,将较小的元素赋值给lc[k],指针k和对应的指针i或j依次后移一位。 3. 重复步骤2,直到某一序列遍历完毕。 4. 将另一序列中剩余的元素全部添加到lc中。 5. 返回新序列lc。 我们还可以使用递归的方式实现归并排序。具体步骤如下: 1. 将待排序序列分两个,直到每部分只有一个元素。 2. 递归地将每个子序列排序、合并,形有序序列,返回给上一层递归。 3. 对于上一层递归返回的两个有序序列,再次进行合并。 4. 返回整个序列的有序结果。 归并排序的时间复杂度为O(nlogn),空间复杂度为O(n)。在数据量较大时,归并排序具有较高的效率和稳定性,因此广泛应用于排序算法中。 ### 回答3: 归并两个有序表需要一个合并过程,首先我们需要创建一个长度为la+lb的新有序表lc。将la和lb的首元素进行比较,将较小的元素放入lc的首元素位置,同时移动该元素所在表的指针到下一个位置。然后再将lc的下一个位置与剩余的la和lb的首元素继续进行比较,将较小的元素放入lc的下一个位置,直到将la和lb的元素全部放入lc中。 在具体实现时,需要定义三个指针,两个分别指向la和lb的首元素,第三个指针指向lc的首元素。比较两个指针所指的元素的大小,将较小的元素放入lc的首元素位置,并移动该元素所在表的指针到下一个位置。然后继续比较两个表头元素,将较小的元素放入lc的下一个位置,依次重复该过程,直到遍历完la和lb的所有元素,此时,lc就是归并后的有序表了。 归并排序利用这种合并有序表的思想进行排序,将原始序列分若干个子序列,先将每个子序列单独排序,然后再将有序的子序列合并一个大的有序序列。归并排序的时间复杂度为O(nlogn),具有稳定性和适用于适合数据量大而分布较为均匀的情况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值