1. 可按如下所述实现归并排序:假设序列中有k个长度为小于等于n的有序子序列。利用过程merge对它们进行两两归并,得到个长度小于等于2n的有序子序列(表示取整),称为一趟归并排序。反复调用一趟归并排序过程,使有序子序列的长度自n=1开始成倍地增加,直至使整个序列成为一个有序序列。试采用链表存储结构实现上述归并排序的非递归算法。函数原型如下:
void Linked_Mergesort(LinkedList &L); //链表结构上的归并排序非递归算法
void Linked_Merge(LinkedList &L, LNode *p, Lnode *e1,Lnode *e2);
/*对链表上的子序列进行归并,第一个子序列是从p->next到e1,第二个是从e1->next到e2*/
答:
void Linked_Mergesort(LinkedList &L); //链表结构上的归并排序非递归算法
{ for(l=1;l<L.length;l*=2)
for(p=L->next,e2=p; p->next; p=e2)
{ for(i=1,q=p; i<=l && q->next; i++,q=q->next)
e1=q;
for(i=1; i<=l && q->next; i++,q=q->next)
e2=q; //求两个待归并子序列的尾指针
if(e1!=e2)
Linked_Merge(L,p,e1,e2);
}
}
void Linked_Merge(LinkedList &L, LNode *p, Lnode *e1,Lnode *e2);
/*对链表上的子序列进行归并,第一个子序列是从p->next到e1,第二个是从e1->next到e2*/
{ q=p->next; //q和r为两个子序列的起始位置
r=e1->next;
while(q!=e1->next && r!=e2->next)
{ if(q->data < r->data)
{ p->next=q;
p=q;
q=q->next;
}
else
{ p->next=r;
p=r;
r=r->next;
}
}
while(q!=e1->next)
{ p->next=q;
p=q;
q=q->next;
}
while(r!=e2->next)
{ p->next=r;
p=r;
r=r->next;
}
}
2.快速排序算法中,如何选取一个界值(又称为轴元素),影响着快速排序的效率,而且界值也并不一定是被排序序列中的一个元素。例如,我们可以用被排序序列中所有元素的平均值作为界值。编写算法实现以平均值为界值的快速排序方法。
解:题目解析:保存划分的第一个元素。以平均值作为枢轴,进行普通的快速排序,最后枢轴的位置存入已保存的第一个元素,若此关键字小于平均值,则它属于左半部,否则属于右半部。
int partition (RecType r[],int l,h)
{ int i=l,j=h,avg=0;
for(;i<=h;i++) avg+=R[i].key;
i=l;
avg=avg/(h-l+1);
while (i<j)
{ while (i<j &&R[j].key>=avg) j--;
if (i<j) R[i]=R[j];
while (i<j &&R[i].key<=avg) i++;
if (i<j) R[j]=R[i];
}
if(R[i].key<=avg) return i;
else return i-1;
}
void quicksort (RecType R[],int S,T);
{if (S<T)
{ k=partition (R,S,T);
quicksart (R,S,k);
quicksart (R,k+1,T);
}
}
3.有一种简单的排序算法,叫做计数排序。这种排序算法对一个待排序的表(用数组表示)进行排序,并将排序结果存放到另一个新的表中。必须注意的是,表中所有待排序的关键字互不相同,计数排序算法针对表中的每个记录,扫描待排序的表一趟,统计表中有多少个记录的关键字比该记录的关键字小。假设对某一个记录,统计出数值为c,那么这个记录在新的有序表中的合适的存放位置即为c。
(1)给出适用于计数排序的数据表定义。
(2)编写实现计数排序的算法。
(3)对于有n个记录的表,比较次数是多少?
(4)与直接选择排序相比,这种方法是否更好?为什么?
解:
(1) typedef struct
{ ElemType data;
KeyType key;
}listtype;
(2) void countsort(listtype a[],listtype b[],int n)
{int i,j,count;
for(i=0;i<n;i++)
{count=0;
for(j=0;j<n;j++)
if(a[j].key<a[i].key) count++;
b[count]=a[i];
}
}
(3) 对于有n个记录的表,关键字比较的次数是n2.
(4)直接选择排序比这种计数排序好,因为直接选择排序的比较次数为n*(n-1)/2,且可在原地进行排序(稳定排序),而计数排序为不稳定排序,需要辅助空间多,为O(n).