一、有序表的定义
- 有序表:是指这样的线性表,其中所有元素以递增或递减方式有序排列。有序表是线性表的一部分。
- 为了简单,假设有序表元素是以递增方式排列。
- 有序表和线性表中元素之间的逻辑关系相同,其区别是运算实现的不同。
二、有序表可以采用与线性表相同的存储结构(顺序表+链表)
(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)