zoukankan      html  css  js  c++  java
  • [数据结构]线性表合并

    一、问题描述

    线性表合并是程序设计语言编译中的一个最基本的问题,现在有两个线性表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!
    ");
     42             return true;
     43         }
     44         RetElem = Elem[Pos - 1];
     45         return false;
     46     }
     47     //LocateElem(L, e, compare()) //返回L中第一个与e满足关系compare()的元素的位序,不存在返回0
     48     bool ElemPos(int El, int &Pos) //若El是L中的元素,返回e的位置,失败时返回true
     49     {
     50         int i;
     51         for(i = 0; i < Len; i++)
     52             if(El == Elem[i])
     53                 break;
     54         if(i < Len)
     55         {
     56             Pos = i + 1;
     57             return false;
     58         }
     59         printf("Cannot find the element!
    ");
     60         return true;
     61     }
     62     bool PriorElem(int El, int &Pre_e) //若El是L中的元素,返回e的前躯,失败时返回true
     63     {
     64         int Pos;
     65         bool flag = ElemPos(El, Pos);
     66         if(flag)
     67         {
     68             printf("Cannot find the element!
    ");
     69             return true;
     70         }
     71         else
     72         {
     73             if(Pos == 1)
     74             {
     75                 printf("Cannot find the precursor!
    ");
     76                 return true;
     77             }
     78             else
     79                 Pre_e = Elem[Pos - 2];
     80         }
     81         return false;
     82     }
     83     bool NextElem(int El, int &Next_e) //若El是L中的元素,返回e的后继,错误时返回true
     84     {
     85         int Pos;
     86         bool flag = ElemPos(El, Pos);
     87         if(flag)
     88         {
     89             printf("Cannot find the element!
    ");
     90             return true;
     91         }
     92         else
     93         {
     94             if(Pos == Len)
     95             {
     96                 printf("Cannot find the successor!
    ");
     97                 return true;
     98             }
     99             Next_e = Elem[Pos];
    100         }
    101         return false;
    102     }
    103     bool ListInsert(int Pos, int El) //在Pos位置插入元素El,失败时返回true
    104     {
    105         if(Pos < 1 || Pos > Len + 1)
    106         {
    107             printf("Wrong position!
    ");
    108             return true;
    109         }
    110         if(Len + 1 > ListSize) //当前存储空间不够,需要增加分配
    111         {
    112             int *NewElem = new int(ListSize + LISTINCREMENT);
    113             int i;
    114             for(i = 0; i < Len; i++)
    115                 NewElem[i] = Elem[i];
    116             delete Elem;
    117             Elem = NewElem;
    118             ListSize += LISTINCREMENT;
    119         }
    120         if(Pos == Len + 1)
    121             Elem[Pos - 1] = El;
    122         else
    123         {
    124             int i;
    125             for(i = Len; i > Pos - 1; i--)
    126                 Elem[i] = Elem[i - 1];
    127             Elem[Pos - 1] = El;
    128         }
    129         Len++;
    130         return false;
    131     }
    132     bool ListDelete(int Pos, int &El) //删除Pos位置的元素,用El返回,错误时返回true
    133     {
    134         if(Pos < 1 || Pos > Len)
    135         {
    136             printf("Wrong position!
    ");
    137             return true;
    138         }
    139         El = Elem[Pos - 1];
    140         int i;
    141         for(i = Pos - 1; i < Len - 1; i++)
    142             Elem[i] = Elem[i + 1];
    143         Len--;
    144         return false;
    145     }
    146     void PrintList()
    147     {
    148         if(ListEmpty())
    149         {
    150             printf("The list is empty!
    ");
    151             return ;
    152         }
    153         int i;
    154         for(i = 0; i < Len - 1; i++)
    155             printf("%d ", Elem[i]);
    156         printf("%d
    ", Elem[i]);
    157     }
    158 };
    159 
    160 void Read(MyList &L)
    161 {
    162     int n, i, Elem;
    163     L.InitList();
    164     printf("Please input a number n.
    ");
    165     scanf("%d", &n);
    166     printf("Please input n non-decreasing numbers.
    ");
    167     for(i = 1; i <= n; i++)
    168     {
    169         scanf("%d", &Elem);
    170         L.ListInsert(i, Elem);
    171     }
    172 }
    173 
    174 void MergeList(MyList La, MyList Lb, MyList &Lc)
    175 {
    176     int aElem, bElem, cLen = 0;
    177     Lc.InitList();
    178     while((!La.ListEmpty()) && (!Lb.ListEmpty()))
    179     {
    180         La.GetElem(1, aElem);
    181         Lb.GetElem(1, bElem);
    182         if(aElem <= bElem)
    183         {
    184             Lc.ListInsert(++cLen, aElem);
    185             La.ListDelete(1, aElem);
    186         }
    187         else
    188         {
    189             Lc.ListInsert(++cLen, bElem);
    190             Lb.ListDelete(1, bElem);
    191         }
    192     }
    193     while(!La.ListEmpty())
    194     {
    195         La.ListDelete(1, aElem);
    196         Lc.ListInsert(++cLen, aElem);
    197     }
    198     while(!Lb.ListEmpty())
    199     {
    200         Lb.ListDelete(1, bElem);
    201         Lc.ListInsert(++cLen, bElem);
    202     }
    203 }
    204 
    205 int main()
    206 {
    207     MyList La, Lb, Lc;
    208     Read(La);
    209     Read(Lb);
    210     MergeList(La, Lb, Lc);
    211     Lc.PrintList();
    212     return 0;
    213 }
    View Code

    1、第二种合并方式,链式表示

      1 #include <iostream>
      2 #include <cstdio>
      3 
      4 using namespace std;
      5 
      6 struct node
      7 {
      8     int Num;
      9     node *next;
     10 };
     11 
     12 class MyList
     13 {
     14 private:
     15     int Len;
     16     node *pHead;
     17 
     18 public:
     19     void InitList()//构造一个空的线性表
     20     {
     21         Len = 0;
     22         pHead = NULL;
     23     }
     24     void ClearList()//重置为空表
     25     {
     26         node *Tmp;
     27         while(pHead)
     28         {
     29             Tmp = pHead;
     30             pHead = pHead -> next;
     31             delete Tmp;
     32         }
     33         Len = 0;
     34     }
     35     bool ListEmpty()//判断L是否为空表
     36     {
     37         return pHead == NULL;
     38     }
     39     int ListLength()//返回L中数据元素个数
     40     {
     41         return Len;
     42     }
     43     bool GetElem(int Pos, int &e)//返回第Pos个元素,出错返回true
     44     {
     45         if(Pos < 1 || Pos > Len)
     46         {
     47             printf("Wrong position!
    ");
     48             return true;
     49         }
     50         node *Cur = pHead;
     51         int Index = 0;
     52         while(++Index < Pos && Cur)
     53             Cur = Cur -> next;
     54         e = Cur -> Num;
     55         return false;
     56     }
     57     //LocateElem(L, e, compare())//返回L中第一个与e满足关系compare()的元素的位序,不存在返回0
     58     bool PriorElem(int e, int &Pre_e)//若e是L中的元素,返回e的前躯,失败时返回true
     59     {
     60         if(pHead -> Num == e)
     61         {
     62             printf("Cannot find the precursor!
    ");
     63             return true;
     64         }
     65         node *Cur = pHead, *Prev;
     66         while(Cur)
     67         {
     68             if(Cur -> Num == e)
     69                 break;
     70             Prev = Cur;
     71             Cur = Cur -> next;
     72         }
     73         if(!Cur)
     74         {
     75             printf("Cannot find the element!
    ");
     76             return true;
     77         }
     78         Pre_e = Prev -> Num;
     79         return false;
     80     }
     81     bool NextElem(int e, int &Next_e)//若e是L中的元素,返回e的后继,错误时返回true
     82     {
     83         node *Cur = pHead;
     84         while(Cur)
     85         {
     86             if(Cur -> Num == e)
     87                 break;
     88             Cur = Cur -> next;
     89         }
     90         if(!Cur)
     91         {
     92             printf("Cannot find the element!
    ");
     93             return true;
     94         }
     95         Cur = Cur -> next;
     96         if(!Cur)
     97         {
     98             printf("Cannot find the successor!
    ");
     99             return true;
    100         }
    101         Next_e = Cur -> Num;
    102         return false;
    103     }
    104     bool ListInsert(int Pos, int e)//在Pos位置插入元素e,失败时返回true
    105     {
    106         if(Pos < 1 || Pos > Len + 1)
    107         {
    108             printf("Wrong position!
    ");
    109             return true;
    110         }
    111         node *InsElem = new node;
    112         if(Pos == 1)
    113         {
    114             InsElem -> next = pHead;
    115             pHead = InsElem;
    116             InsElem -> Num = e;
    117         }
    118         else
    119         {
    120             node *Cur = pHead;
    121             int Index = 0;
    122             while(++Index + 1 < Pos && Cur)
    123                 Cur = Cur -> next;
    124             InsElem -> next = Cur -> next;
    125             Cur -> next = InsElem;
    126             InsElem -> Num = e;
    127         }
    128         Len++;
    129         return false;
    130     }
    131     bool ListDelete(int Pos, int &e)//删除Pos位置的元素,用e返回,错误时返回true
    132     {
    133         if(Pos < 1 || Pos > Len)
    134         {
    135             printf("Wrong position!
    ");
    136             return true;
    137         }
    138         node *DelElem = pHead;
    139         if(Pos == 1)
    140         {
    141             pHead = DelElem -> next;
    142             e = DelElem -> Num;
    143             delete DelElem;
    144         }
    145         else
    146         {
    147             node *Prev;
    148             int Index = 0;
    149             while(++Index < Pos && DelElem)
    150             {
    151                 Prev = DelElem;
    152                 DelElem = DelElem -> next;
    153             }
    154             Prev -> next = DelElem -> next;
    155             e = DelElem -> Num;
    156             delete DelElem;
    157         }
    158         Len--;
    159         return false;
    160     }
    161     //ListTraverse(L, visit())//依次对L中的每个数据元素调用函数visit(),一旦visit()失败,则操作失败
    162     void PrintList()
    163     {
    164         if(ListEmpty())
    165         {
    166             printf("The List is empty!
    ");
    167             return ;
    168         }
    169         node *Cur = pHead;
    170         int Index = 0;
    171         while(++Index < Len && Cur)
    172         {
    173             printf("%d ",Cur -> Num);
    174             Cur = Cur -> next;
    175         }
    176         printf("%d
    ",Cur -> Num);
    177     }
    178     bool ElemPrio(node a, node b)
    179     {
    180         return a.Num < b.Num;
    181     }
    182     void MergeList(MyList Lb) //把Lb插入L中
    183     {
    184         int aElem, bElem, aIndex = 0;
    185         while(aIndex < Len && (!Lb.ListEmpty()))
    186         {
    187             GetElem(++aIndex, aElem);
    188             Lb.GetElem(1, bElem);
    189             if(aElem > bElem)
    190             {
    191                 Lb.ListDelete(1, bElem);
    192                 ListInsert(aIndex, bElem);
    193             }
    194         }
    195         while(!Lb.ListEmpty())
    196         {
    197             Lb.ListDelete(1, bElem);
    198             ListInsert(Len + 1, bElem);
    199         }
    200     }
    201 };
    202 
    203 void Read(MyList &L)
    204 {
    205     int n, i, Elem;
    206     L.InitList();
    207     printf("Please input a number n.
    ");
    208     scanf("%d", &n);
    209     printf("Please input n non-decreasing numbers.
    ");
    210     for(i = 1; i <= n; i++)
    211     {
    212         scanf("%d", &Elem);
    213         L.ListInsert(i, Elem);
    214     }
    215 }
    216 
    217 int main()
    218 {
    219     MyList La, Lb;
    220     Read(La);
    221     Read(Lb);
    222     La.MergeList(Lb);
    223     La.PrintList();
    224     return 0;
    225 }
    View Code
  • 相关阅读:
    顺序前缀改为随机性前缀 反转时间戳 反转年月日
    后台组件的治理思路
    干货 | 高耦合场景下,Trip.com如何做支付设计与落地
    每天响应数亿次请求,腾讯云如何提供高可用API服务?
    系统管理及操作命令
    远程连接及系统管理
    linux系统部署安装过程
    day 1 硬件组成概念及介绍笔记
    day 4
    day 3
  • 原文地址:https://www.cnblogs.com/CQBZOIer-zyy/p/5185414.html
Copyright © 2011-2022 走看看