数据结构学习(九):有序表

一、有序表的定义

  1. 有序表:是指这样的线性表,其中所有元素以递增或递减方式有序排列。有序表是线性表的一部分。
  2. 为了简单,假设有序表元素是以递增方式排列。
  3. 有序表和线性表中元素之间的逻辑关系相同,其区别是运算实现的不同。

二、有序表可以采用与线性表相同的存储结构(顺序表+链表)

(1)若以顺序表存储有序表,基本运算算法中只有Listinsert()算法与前面的顺序表对应的运算有差异,其余都是相同的

      有序顺序表的ListInsert()算法如下:
  void  ListInsert(SqList *&L,ElemType e)
  {
       int i=0,j;
       while(i<L->length && L->data[i]<e)   //查找值为e的元素
                 i++;
       for(j=ListLength(L);j>i;j--)      //将data[1....n]后移一个位置
                 L->data[i]=L->data[i-1];
       L->data[i]=e;
       L->length++;         //有序表的长度增加1
  }

(2)若以单链表存储有序表,同样基本运算算法中只有Listinsert()算法与前面的顺序表对应的运算有差异,其余都是相同的

      有序单链表的ListInsert()算法如下:
    void  ListInsert(LinkList *&L,ElemType e)
    {
         LinkList *pre=L,*p;
         while(pre->next!=NULL && pre->next->data[i]<e)   //查找插入节点的前趋节点*pre
                   pre=pre->next;
         p=(LinkList *)malloc(sizeof(LinkList));
         p->data=e;        //创建存放e的数据节点*p
         p->next=pre->next;  //在*pre节点之后插入*p节点
         pre->next=p;
    }

三、有序表的归并运算

假设有两个有序表LA和LB,设计一个算法,将他们合并成一个有序表LC(二路归并思想)

(1)采用顺序表存放有序表时,二路归并算法如下:

         void  UnionList(SqList *LA,SqList *LB,SqList *&LC)
         {
                int i=0,j=0,k=0;    //i、j分别为LA、LB的下标,k为LC中元素的个数
                LC=(SqList *)malloc(sizeof(SqList ));  //建立有序顺序表LC
                while(i<LA->length && j<LB->length)    //两个有序表均没有遍历完
                {
                         if(LA->data[i]<LB->data[j])
                         {
                               LC->data[k]=LA->data[i];
                               i++;  k++;
                         }
                         else
                         {
                               LC->data[k]=LB->data[j];
                               j++;  k++;
                         }
                }
                while(i<LA->length)                        //LA尚未扫描完,将其余元素插入LC中
                         {
                               LC->data[k]=LA->data[i];
                               i++;  k++;
                         }
                while(j<LB->length)                           //LB尚未扫描完,将其余元素插入LC中
                         {
                               LC->data[k]=LB->data[j];
                               j++;  k++;
                         }
             LC->length=k;
          }
   //本算法的时间复杂度为O(m+n),空间复杂度为O(m+n)

(2)采用单链表存放有序表时,二路归并算法如下:

    void  UnionList(LinkList *LA,LinkList *LB,LinkList *&LC)
         {
                LinkList *pa=LA->next,*pb=LB->next,*r,*s;
                LC=(LinkList *)malloc(sizeof(LinkList ));  //建立LC的头节点
                r=LC;                                                      //r始终指向LC的尾节点
                while(pa!=NULL && pb!=NULL)    //两个有序表均没有遍历完
                {
                         if(pa->data<pb->data)
                         {
                               s=(LinkList *)malloc(sizeof(LinkList ));  //建立节点
                               s->data=pa->data;
                               r->next=s;  r=s;                            //采用尾插法将*s插入到LC中
                               pa=pa->next;
                         }
                         else
                         {
                               s=(LinkList *)malloc(sizeof(LinkList ));  //建立节点
                               s->data=pb->data;
                               r->next=s;  r=s;                            //采用尾插法将*s插入到LC中
                               pb=pb->next;
                         }
                }
                while(pa!=NULL)                           //LA尚未扫描完,将其余元素插入LC中
                         {
                               s=(LinkList *)malloc(sizeof(LinkList ));  //建立节点
                               s->data=pa->data;
                               r->next=s;  r=s;                            //采用尾插法将*s插入到LC中
                               pa=pa->next;
                         }
                         while(pb!=NULL)                           //LB尚未扫描完,将其余元素插入LC中
                         {
                               s=(LinkList *)malloc(sizeof(LinkList ));  //建立节点
                               s->data=pb->data;
                               r->next=s;  r=s;                            //采用尾插法将*s插入到LC中
                               pb=pb->next;
                         }
             r->next=NULL;                     //尾节点的next域置空
          }
   //本算法的时间复杂度为O(m+n),空间复杂度为O(m+n)

四、[2011年全国考研题]一个长度为L (L≥1)的升序序列S,处在第 L/2 个位置的数称为S的中位数。

例如:若序列S,=(11,13,15,17,19),则S1的中 位数是15。 两个序列的中 位数是含它们所有元素的升序序列的中位数。
     若S,=(2,4,6,8,20),则S和S,的中位数是11。现有两个等 长的升序序列A和B,
     试设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列A和B的中位数。要求:
     (1) 给出算法的基本设计思想。
     (2)根据设计思想,采用C、C++或Java语言描述算法,关键之处给出注释
     (3)说明你所设计算法的时间复杂度和空间复杂度。

标准答案:

  • (1)实际上,不要要求出S的全部元素,用k记录当前归并的元素个数,当k=n时归并的那个元素就是中位数

  • (2)

   int M_Search(int A[],int B[],int n)
   {
       int i,j,k;
       i=j=k=0;
       while(i<n && j<n)
       {
            k++;
            if(A[i]<B[i])
            {
                if(k==n)  return A[i];
                i++;
             }
             else
             {
                 if(k==n)  return B[j];
                 j++;
             }
        }
    }
      
  • (3)算法的时间复杂度为O(n),空间复杂度为O(1)

你可能感兴趣的:(数据结构(C语言))