算法与数据结构考研试题精析(第二版)第10章 排序
数据结构第10章

算法评价(参考)
时间复杂度
若待排序记录按关键字从小到大排列(正序) 关键字比较次数: 记录移动次数:0 若待排序记录按关键字从大到小排列(逆序)
1 n 1
i 2
n
(n 2)(n 1) 2 i 2 n (n 4)(n 1) 记录移动次数: (i 1) 2 i 2
时间复杂度:O(nlogn)
10.3 快速排序分析
快速排序在最好情形下(左、右子区间的长度
大致相等),则结点数n与二叉树深度h应满足 log2n<h<log2n+1,所以总的比较次数不会超 过(n+1)log2n。因此,快速排序的最好时间复 杂度应为O(nlog2n)。理论上已经证明,快速 排序的平均时间复杂度也为O(nlog2n)。 在最坏情况下(逆序或正序),时间复杂度为 O(n2) 空间复杂度:O(logn)
10.3 交换排序 冒泡排序 排序过程
将第一个记录的关键字与第二个记录的关
键字进行比较,若为逆序r[1].key>r[2].key, 则交换;然后比较第二个记录与第三个记 录;依次类推,直至第n-1个记录和第n个 记录比较为止——第一趟冒泡排序,结果 关键字最大的记录被安置在最后一个记录 上 对前n-1个记录进行第二趟冒泡排序,结果 使关键字次大的记录被安置在第n-1个记录 位置 重复上述过程,直到“在一趟排序过程中 没有进行过交换记录的操作”为止
假设含 n 个记录的序列为 { R1 ,R2 ,…,Rn } 其相应的关键字序列为 { K1,K2,…,Kn } 需确定1,2,…,n的一种排列 p1,p2,…,pn 使关键字满足非递减(或非递增)关系 Kp1≤Kp2≤…≤Kpn 即使初始的的序列成为一个按关键字有序的 序列 { Rp1,Rp2,…,Rpn} 这样一种操作称为排序。
中南大学数据结构与算法第10章内部排序课后作业答案

第10章内部排序习题练习答案1.以关键字序列(265,301,751,129,937,863,742,694,076,438)为例,分别写出执行以下排序算法的各趟排序结束时,关键字序列的状态。
(1) 直接插入排序(2)希尔排序(3)冒泡排序(4)快速排序(5) 直接选择排序(6) 堆排序(7) 归并排序(8)基数排序上述方法中,哪些是稳定的排序?哪些是非稳定的排序?对不稳定的排序试举出一个不稳定的实例。
答:(1)直接插入排序:(方括号表示无序区)初始态: 265[301 751 129 937 863 742 694 076 438]第一趟:265 301[751 129 937 863 742 694 076 438]第二趟:265 301 751[129 937 863 742 694 076 438]第三趟:129 265 301 751[937 863 742 694 076 438]第四趟:129 265 301 751 937[863 742 694 076 438]第五趟:129 265 301 751 863 937[742 694 076 438]第六趟:129 265 301 742 751 863 937[694 076 438]第七趟:129 265 301 694 742 751 863 937[076 438]第八趟:076 129 265 301 694 742 751 863 937[438]第九趟:076 129 265 301 438 694 742 751 863 937(2)希尔排序(增量为5,3,1)初始态: 265 301 751 129 937 863 742 694 076 438第一趟:265 301 694 076 438 863 742 751 129 937第二趟:076 301 129 265 438 694 742 751 863 937第三趟:076 129 265 301 438 694 742 751 863 937(3)冒泡排序(方括号为无序区)初始态[265 301 751 129 937 863 742 694 076 438]第一趟:076 [265 301 751 129 937 863 742 694 438]第二趟:076 129 [265 301 751 438 937 863 742 694]第三趟:076 129 265 [301 438 694 751 937 863 742]第四趟:076 129 265 301 [438 694 742 751 937 863]第五趟:076 129 265 301 438 [694 742 751 863 937]第六趟:076 129 265 301 438 694 742 751 863 937(4)快速排序:(方括号表示无序区,层表示对应的递归树的层数)初始态:[265 301 751 129 937 863 742 694 076 438]第二层:[076 129] 265 [751 937 863 742 694 301 438] 第三层:076 [129] 265 [438 301 694 742] 751 [863 937] 第四层:076 129 265 [301] 438 [694 742] 751 863 [937] 第五层:076 129 265 301 438 694 [742] 751 863 937第六层:076 129 265 301 438 694 742 751 863 937 (5)直接选择排序:(方括号为无序区)初始态[265 301 751 129 937 863 742 694 076 438]第一趟:076 [301 751 129 937 863 742 694 265 438]第二趟:076 129 [751 301 937 863 742 694 265 438]第三趟:076 129 265[ 301 937 863 742 694 751 438]第四趟:076 129 265 301 [937 863 742 694 751 438]第五趟:076 129 265 301 438 [863 742 694 751 937]第六趟:076 129 265 301 438 694 [742 751 863 937]第七趟:076 129 265 301 438 694 742 [751 863 937]第八趟:076 129 265 301 438 694 742 751 [937 863]第九趟:076 129 265 301 438 694 742 751 863 937(6)堆排序:(通过画二叉树可以一步步得出排序结果)初始态[265 301 751 129 937 863 742 694 076 438]建立初始堆:[937 694 863 265 438 751 742 129 075 301]第一次排序重建堆:[863 694 751 765 438 301 742 129 075] 937第二次排序重建堆:[751 694 742 265 438 301 075 129] 863 937第三次排序重建堆:[742 694 301 265 438 129 075] 751 863 937第四次排序重建堆:[694 438 301 265 075 129] 742 751 863 937第五次排序重建堆:[438 265 301 129 075] 694 742 751 863 937第六次排序重建堆:[301 265 075 129] 438 694 742 751 863 937第七次排序重建堆:[265 129 075] 301 438 694 742 751 863 937第八次排序重建堆:[129 075]265 301 438 694 742 751 863 937第九次排序重建堆:075 129 265 301 438 694 742 751 863 937(7)归并排序(为了表示方便,采用自底向上的归并,方括号为有序区)初始态:[265] [301] [751] [129] [937] [863] [742] [694] [076] [438]第一趟:[265 301] [129 751] [863 937] [694 742] [076 438]第二趟:[129 265 301 751] [694 742 863 937] [076 438]第三趟:[129 265 301 694 742 751 863 937] [076 438]第四趟:[076 129 265 301 438 694 742 751 863 937](8)基数排序(方括号内表示一个箱子共有10个箱子,箱号从0到9)初始态:265 301 751 129 937 863 742 694 076 438第一趟:[] [301 751] [742] [863] [694] [265] [076] [937] [438] [129]第二趟:[301] [] [129] [937 438] [742] [751] [863 265] [076] [] [694]第三趟:[075] [129] [265] [301] [438] [] [694] [742 751] [863] [937]在上面的排序方法中,直接插入排序、冒泡排序、归并排序和基数排序是稳定的,其他排序算法均是不稳定的,现举实例如下:以带*号的表示区别。
数据结构第十章排序

i2
2
n
记录移动次数:
(i 1) (n 4)(n 1)
i2
2
若待排序记录是随机的,取平均值
关键字比较次数: n 2
4
记录移动次数: n 2 • 空间复杂度:S(n)=O(1)4
T(n)=O(n²)
折半插入排序
排序过程:用折半查找方法确定插入位置的排序叫~
例 i=1
(30) 13 70 85 39 42 6 20
第十章 排序
10.1 插入排序 10.2 交换排序 10.3 选择排序 10.4 归并排序 10.5 基数排序 10.6 各种排序方法的综合比较
排序定义——将一个数据元素(或记录)的任意 序列,重新排列成一个按关键字有序的序列叫~
排序分类
按待排序记录所在位置
• 内部排序:待排序记录存放在内存 • 外部排序:排序过程中需对外存进行访问的排序
• 对前n-1个记录进行第二趟冒泡排序,结果使关键 字次大的记录被安置在第n-1个记录位置
• 重复上述过程,直到“在一趟排序过程中没有进 行过交换记录的操作”为止
例
4398 38 38 38 3183 13 13
3489 49 49 4193 132387 27 27
65 65 6153 142397 23780 30 30
例 含8个元素的无序序列(49,38,65,97,76,13,27,50)
49
38
65
97 76 13 27
50
49
38
65
50 76 13 27
97
49
38
13
50 76 65 27
97
49
38
13
50 76 65 27
数据结构预算法第十章排序

❖ { 35 48 62 77 } 55 14 35 98
❖ { 35 48 55 62 77 } 14 35 98
❖ { 14 35 48 55 62 77 } 35 98
❖ { 14 35 35 48 55 62 77 } 98
❖ { 14 35 35 48 55 62 77
98 }
数据结构预算法第十章排序
d=5 4 3 2 1 0 9 8 7 6 5 (d=5执行结果) d=2 0 1 2 3 4 5 6 7 8 9 (d=2执行结果) d=1 0 1 2 3 4 5 6 7 8 9 (d=1执行结果)
数据结构预算法第十章排序
10.3 快速排序
❖ 快速排序又称为交换排序,是根据记录的关键字的大小,通 过记录交换来实现排序的。
将大大增加,对于有序表,为了减少关键字的比较次数,可 采用二分插入排序。 ❖ 2.效率分析 ❖ 二分插入排序是稳定的排序。时间复杂度和空间复杂度和直 接插入排序的一样。
数据结构预算法第十章排序
❖ 10.2.3 希尔排序
❖ 希尔排序又称“缩小增量排序”,它也是一种插入排 序的方法,但时间上比前两种排序方法有比较大的改 进。
第三趟希尔排序,设增量 d = 1
9 11 12 16数据1结8构预算2法3第十2章5排序30 31 36 47
例 设 待 排 序 的 表 有 10 个 记 录 , 其 关 键 字 分 别 为 {9,8,7,6,5,4,3,2,1,0}。说明采用希尔排序方法进行排序的过程。
初始状态 9 8 7 6 5 4 3 2 1 0 (连线部分为下一趟作准备)
数据结构预算法第十章排序
❖ 10.2.2 二分插入排序
Hale Waihona Puke 插入位置i
数据结构(c语言版)题集答案——第十章_内部排序.docx

第十章内部排序10.23void Insert_Sortl(SqList &L)〃监视哨设在高下标端的插入排序算法{k=L」ength;for(i=k-l;i;-i)//从后向前逐个插入排序if(L.r[i].key>L.r[i+1] .key){L.r[k+l].key=L.r[i].key;// 监视哨for(j=i+l;L.rfj].key>L.r[i].key;4-+j)L.r [j-1 ] .key=L.r[j] .key; 〃前移L.r [j-1 ] .key=L.r[k+1 ] .key; 〃插入}}//Insert_Sortl10.24void BiInsert_Sort(SqList &L)〃二路插入排序的算法{int dlMAXSIZE];//辅助存储x=L.r .key;d =x;first= 1 ;final= 1;for(i=2;i<=L.length;i++){if(L.r[i].key>=x) //插入前部{for(j=final;d[j]>L.r[i].key;j—)dU+l]=dU];d[j+l]=L.r[i].key;final++;}else//插入后部{for(j=first;d[j]d[j-l]=d[j];dl(j-2)%MAXSIZE+ l]=L.r[iJ.key;first=(first-2)%MAXSIZE+1; //&种形式的表达式是为了兼顾first=l的情况}}//forfor(i=first j= 1 ;dLiJ ;i=i%MAXS!ZE+1 ,j++)//^l 各序列复制回去L.r[j].key=d[i];}//BiInsert_Sort10.25void SLInsert_Sort(SLList &L)〃静态链农的插入排序算法L.r[0].key=0;L.r[0].next=l;L.r[l].ncxt=O; 〃建初始循环链表for(i=2;i<=L.length;i++) // 逐个插入{p=O;x=L.r[i].key;while(L.rLL.r[p].next].keyp=L.r[p].next;q=L.r[p].next;L.r[p].ncxt=i;L.r[i].next=q;}//forp=L.r[OJ.next;for(i=l;i{whilc(pq=L.r[p].ncxt;if(p!二i){L.r[pJ<->L.r[iJ;L.r[i].next=p;}p=q;}//for}//SLInsert_Sort10.26void Bubble_Sortl(int a[ ],int n)〃对包含n个元素的数组a进彳亍改进的冒泡排序{change=n-l; //change指示上一趟冒泡中最后发生交换的元素while(change){for(c=0,i=0;iif(a[i]>a[i+1]){a[i]<->a[i+l];c=i+l;//c指示这一趟冒泡屮发生交换的元素}changc=c;}//while}//Bubble_Sortl10.27void Bubblc_Sort2(int a[ ],int n)〃相邻两趟是反方向起泡的冒泡排序算法{low=0;high=n-1; 〃冒泡的上F界change=l;while(low{change=():for(i=low;iif(a[i]>a[i+1])chanse=l:}high-;//修改上界for(i=high;i>low;i-) //从F 向上起泡a[i]<->a[i-l];changc=l;}low++;〃修改卜-界}//while}//Bubble_Sort210.28void Bubble_Sort3(int a[ ],int n)〃对上一题的算法进行化简,循环体中只包含一次冒泡{int b[ 3 ]; //b[0]为冒泡的下界,b[ 2 ]为上界,b[l]无用d=l;b[0]=0;b[2]=n-l;//d为冒泡方向的标识,1为向上,・1为向下changc=l;while(b[0]{change=0;for(i=b[l -dl ;i!=bfl +d] ;i+=d) // 统一的冒泡算法if((a[i]・a[i+d])*d>0)//注意这个交换条件{a[i]<->a[i+d];change=l;}b[l+d]-=d; //修改边界d*=-l;〃换个方向}//while}//Bubble_Sort310.29void OE_Sort(int a[ ],int n)〃奇偶交换排序的算法{change=l;while(cha nge){change=():for(i= 1 ;iif(a[i]>a[i+1]){a[i]<->a[i+l];change=l;}for(i=0;iif(a[i]>a[i+1])}}//while}//OE_Sort分析:木算法的结束条件是连续两趟比较无交换发生10.30typcdcf struct {int low;int high;} boundary; //了序列的上下界类型void QSort_NotRecurve(int SQList &L)〃快速排序的非递归算法{low= 1 ;high=L.length;InitStack(S); //S 的元素为boundary 类型while(low{if(high-Iow>2) //如果当前了序列氏度大于3 尚未排好序{pivot=Partition(L,low,high); 〃进行一趟划分if(high-pivot>pivot-low){Push(S,{pivot+1 ,high}); //把长的了序列边界入栈high=pivot-l; 〃短的子序列留待下次排序}else{Push(S,{ low,pivot-1});low=pivot+l;}}〃讦else if(low{Easy_Sort(L,low,high); //直接进行比较排序low=high; 〃当前子序列标,忐为已排好序}else//如果当前子序列己排好序但栈屮还有未排序的子序列{Pop(S,a); 〃从栈中取出一个了序列low=a.low;high=a.high;}}//while}//QSort_NotRecurveint Partition(SQList &L,int low,int high)//-•趟划分的算法,与书上相同L.r[0]=L.r[low];pivotkey=L.r[low] .key;while(low=pivotkey)high-;L.r[low]=L.r[high];while(lowlow++;L.r[high]=L.r[low];}//whileL.r[lowJ=L.r[OJ;return low;{//Partitionvoid Easy_Sort(SQList &L,int low,int high)//对长度小于3的子序列进行比较排序{if(high-low==l)//子序列只含两个元索if(L.r[low] .key>L.r[high] .key) L.r[low]<->L.r[high];C1SC//T序列含冇三个元素{if(L.r[low].key>L.r[low+ l].key) L.r[low]<->L.r[low+1 ];if(L.r[low+1 J.key>L.r[high].key) L.r[low+1 J<->L.r[high];if(L.r[low].key>L.r[low+ l].key) L.r[low]<->L.r[low+ 1J;}}//Easy_Sort10.31void Divide(int a[ l,int n)〃把数组a中所有值为负的记录调到非负的记录ZMj{low=();high=n-l;whilc(low{while(low=0) high-; 〃以0作为虚拟的枢轴记录a[lowJ<->aLhighJ;while(lowallow]<->a[high];}[//Divide10.32typedef enum {RED,WHITE,BLUE} color; //三种颜色void Flag_Arrange(color a[ ],int n)〃把由三种颜色组成的序列重排为按照红,白,蓝的顺序排列{i=0;j=0;k=n-1;while(j<=k)switch(a[jj){case RED:i++;j++;break;case WHITE:j++;break;case BLUE:a[j]<->a[k];k-; 〃这里没有j++;语句是为了防止交换后a[j]仍为蓝色的情况}}//Flag_Arrange分析:这个算法屮设立了三个指针.其屮,j表示当前元素;i以前的元素全部为红色;k以示的元索全部为蓝色.这样,就可以根据j的颜色,把其交换到序列的前部或者后部.10.33void LinkedList_Select_Sort(LinkedList &L)〃单链表上的简单选择排序算法{for(p=L;p->next->next;p=p->next){q=p->ncxt;x=q->data;for(r=q,s=q;r->next;r=r->next)//?l: q后面寻找元素值最小的结点if(「>n ext->data{x=r- >n ext->data;s=r;}if(s!=q) //找至【J了值比q->data更小的最小结点s->next{p->next=s->next;s->next=q;(二q・> next;q・>next二pp->ncxt->ncxt=t;} 〃交换q和s->next两个结点}//for}//LinkedList_Select_Sort10.34void Build_Heap(Heap &H,int n)〃从低下标到高下标逐个插入建堆的算法{for(i=2;i{ 〃此时从H.r[l]到H.r[i・l]己经是大顶堆• •J=l;while(j!=l)//把H.r[i]插入{k=j/2;if(H.r|j] .key>H.r[kJ .key)H.r[j]<->H.r[k];j=k;}}//for}//Build_Heap10.35void TriHeap_Sort(Heap &H)〃利用三叉树形式的堆进行排序的算法{for(i=H.length/3;i>0;i—)Heap_Adjust(H,i,H.length);for(i=H」ength;i>l;i—){H.r[l]<->H.r[i];Heap_Adjust(H, 1 ,i-l);}}//TriHeap_Sortvoid Heap_Adjust(Heap &H,int s,int m)//顺序表H 中,H.r[s+1]到H.r[m]已经是堆,把H.r[s]插入并调整成堆{rc=H.r[s];for(j=3 *s-1 ;j<=m;j=3 *j-1){s=j;}H.rfs]=rc;}//Heap_ Adjust分析:本算法与课本上的堆排序算法相比,只有两处改动:1.建初始堆时,i的上限从H.length/3 开始(为什么?)2.调整堆的时候,要从结点的三个孩子结点中选择最大的那一个,最左边的孩子的序号的计算公式为j=3*s・l(为什么?)10.36void Merge_Sort(int a[ ],int n)〃归并排序的非递归算法{for(l= 1 ;lfor(i=0;(2*i-l)*l{start 1 =2*1 *i; //求出待归并的两段的上下界end l=start 1+1-1;start2=cnd 1+1;end2=(start2+l-1 )>(n-1 )?(n-1 )start2+l-1);//注意end2 可能超出边界Merge(a,start 1 ,end 1 ,start2,end2); 〃归)[■}}//Merge_Sortvoid Merge(int a[ ],int sl,int el,int s2,int e2)〃将有序子序列a[sl]到a[el]和a[s2]到a[e2]归并为有序序列a[sl]到a[e2]{int bfMAXSIZE]; 〃设立辅助存储数组bfor(i=s 1 ,j=s2,k=s 1 ;i<=e 1 &&jv二e2;k++) if(a[i]else b[k]=a[j++]; while(i<=el) b[k++]=a[i++];while(j<=e2) b[k++]=a[j++];〃归并到b 屮for(i=s 1 ;i<=e2;i++) // 复制回去a[iJ=bLiJ;}//Merge10.37void LinkedList_Merge_Sort 1 (LinkedList &L)〃链农结构上的归并排序非递归算法{for(l= 1 ;lfor(p=L->next,e2=p;p->next;p=e2){for(i= 1 ,q=p;i<=l&&q->next;i++,q=q->next);cl=q;for(i= l;i<=l&&q->next;i++,q=q->next);e2=q; 〃求出两个待归并子序列的尾指针if (el !=e2) LinkedList_Merge(L,p,el,e2); // 归并}}//LinkcdList_Mcrgc_Sort 1void LinkedList_Merge(LinkedList &L,LNode *p,LNode *el,LNode *e2)〃対链表上的子序列进行归并,第一个子序列是从p->next到el,第二个是从e 1 ->next到e2{q=p->ncxt;r=c 1 ->ncxt; //q和r为两个了序列的起始位置while(q!=el->next&&r!=e2->next){if(q->datadata) //^择关键字较小的那个结点接在p的后而{p->next=q;p=q;q=q->ncxt;}else{p->next=r;p=r;r=r->ncxt;}}//whilewhile(q!=el->next) //接上剩余部分{p->ncxt=q;p=q;q=q->next;}while(r!=e2->next){p->next=r;p=r;r=r->next;}//LinkedList_Merge10.38void LinkedList_Merge_Sort2(LinkedList &L)〃初始归并段为最大有序子序列的归并排序,采用链表存储结构{LNodc *cnd[MAXSIZE]; 〃设立一个数组来存储各冇序了序列的尾指针for(p=L->next->nextj=0;p;p=p->next) // 求各有序子序列的尾指针if(!p->nextllp->data>p->next->data) end[i++]=p;while(end[O]->next) //当不止一个子序列时进行两两归并{j=O;k=O;//j:当前子序列尾指针存储位B!;k:归并后的子序列尾指针存储位置for(p=L->next,e2=p;p->next;p=e2) //两两归并所有子序列{el二end[j];e2=end[j+l]; //确定两个子序列if(e 1 ->next) LinkedList_Merge(L,p,e 1 ,e2); 〃归并cnd[k++]=c2; //用新序列的尾指针取代原来的尾指针j+=2;〃转到后面两个子序列}}//while}//LinkedList_Merge_Sort2void LinkcdList_Mcrgc(LinkcdList &L,LNodc *p,LNodc *cl,LNodc *c2)〃对链表上的了序列进行归并,第一个了序列是从p->next到el,第二个是从el->next到e2{q=p->next;r=e 1 ->next;while(q!=e 1 ->next&&r!=e2->next){if(q->datadata){p->next=q;p=q;q=q->next;}else{p->next=r;p=r;r=r->next;}}//whilewhile(q!=e 1 ->next){p->next=q;p=q;q=q->next;}while(r!=e2->next)p->next=r;p=r;}//LinkedList_Merge,与上一题完全相同10.39void SL_Mcrgc(int a[ ],int ll,int 12)//把长度分别为11,12且11A2<(11+12)的两个有序子序列归并为有序序列{startl=0;start2=ll;//分别表示序列1和序列2的剩余未归并部分的起始位直for(i=0;i{for(j=start2;jk=j-start2; //k为要向右循环移动的位数RSh(a,start 1 j-1 ,k);//W a[startl]到a[j・l]之间的子序列循环右移k位start l+=k+l;start2=j; 〃修改两序列尚未归并部分的起始位置}}//SL_Mergevoid RSh(int a[ ] jnt start,int end,int k)〃将a[start]到a[end]之间的子序列循环右移k 位,算法原理参见5.18{len=end-start+l;for(i=l;i<=k;i++)if(len%i==0&&k%i==0) p=i; 〃求len 和k 的最大公约数pfor(i=0;i{j=start+i;l=start+(i+k)%len;temp=a|jj;while(l!=start+i){a[j]=tcmp;temp=a[l];all]=a|j];j=l;l=start+(j-start4-k)%len; // 依次|H J右移}a[start+i]=temp;}//for}//RSh10.40E后给出的解题思路在表述上存在问题,无法理解•比如说,“把第一个序列划分为两个子序列, 使其中的第一个子序列含有si个记录,0<=s 110.41void Hash_Sort(int a[ J)//X'j 1000个关键字为四位整数的记录进行排序{int b[ 10000];for(i=0;ivl000;i卄)〃直接按关键字散列{for(j=a[i] ;b[j] ;j=(j+1)% 10000);fo「(i=0,j=0;ivl000;j++)〃将散列收回a 中if(b[j]){for(x=b[j],k=j ;b[kj ;k=(k+1)%10000)if(b[k>=x){a[i++]=x;b[k]=0;}}//if}//Hash_Sort10.42typedef stmct {int gt; //大于该记录的个数int It; 〃小于该记录的个数} place; 〃整个序列中比某个关键字大或小的记录个数int Get_Mid(int a[ J,int n)〃求一个序列的中值记录的位置{place b[MAXSIZEJ;for(i=();ifor(j=0;j{if(a[j]>a[i])b[i].gt++;else if(a[j]}mid=0;min_dif=abs(b[0].gt-b[0].lt);for(i=0;iif(abs(b[i].gt-b[i].lt)return mid;}//Gct_Mid10.43void Count_Sort(int a[ ],int n)〃计数排序算法{int cfMAXSIZE];for(i=0;i{for(j=0,count=0;jif(a[j]c[i]=count;}for(i=0;i{min=();for(j=0;jif(c[j]a[i]<->a[min]; 〃与第i 个记录交换c[minJ=INFINITY; //修改该记录的c值为无穷大以便下一次选収}}//Count_Sort10.44void Enum_Sort(int a[ ],int n)〃对关键字只能取v到w Z间任意整数的序列进行排序int number[w+1 J,pos[w+1J; for(i=0;ifor(pos[0]=0,i=l;ipos[i]=pos[i-l]+num[i]; //pos 数组可以把关键字的值映射为元素在排好的序列中的位置for(i=0;ic[pos[a[i]]++]=a[i];for(i=0;ia[i]=c[i];}//Enum_Sort分析:木算法参考了第五章三元组稀疏矩阵转置的算法思想,其中的pos数组和那里的cpot数组起的是相类似的作用.10.45typedef enum {0,1,2,3,4,5,6,7,8,9} digit; //个位数类型typedef digit[3] num; //3位自然数类型,假设低位存储在低下标,高位存储在高卜•标void Enuni_Radix_Sort(num a[ ],int n)〃利用计数实现基数排序,其屮关键字为3位白然数,共有n个自然数{int number ,pos ;num c[MAXSIZEJ;for(j=0;j<3;j++) //依次对个位,十位和百位排序{for(i=0;ifor(pos[0]=0,i=l;ipos[iJ=pos[i-l]+numLi]; //把关键字的值映射为元素在排好的序列中的位置for(i=0;ic[pos[a[ij[j]]++]=a[i];for(i=0;ia[i]=c[i];}//for}//Enum_Radix_Sort分析:计数排序是一种稳定的排序方法.」E因为如此,它才能够被用来实现基数排序.10.46typedef struct {int key;int pos;} Shadow;//影子序列的记录类型void Shadow_Sort(Rectype b[ ],Rectype &a[ ],int n)〃对元素很人的记录序列b进行排序,结果放入a中,不移动元素{Shadow d[MAXSIZE];for(i=0;i{d[i].key=b[i].key;dfi].pos=i;}for(i=n-l ,change= 1 ;i> 1 &&change;i・・)//对影子序列执行冒泡排序{change=0;for(j=O;jif(d[j].key>d[j+l].key){dU]<->dU+U;change=l;}//forfor(i=0;ia[i]=b[d[i].pos]; }//Shadow_Sort。
数据结构与算法》课件 第10章 排序

第10章 内部排序
10.1 10.2 10.3 10.4 10.5 10.6 概述 插入排序 交换排序 选择排序 归并排序 基数排序
10.1
概述
1. 什么是排序? 将一组杂乱无章的数据按一定的规律顺次排列起来。
存放在数据表中 按关键字排序
定义:设有记录序列:{ R1、R2 ……….. Rn } 其相应的关键字序列为: { K1、K2 ……….. Kn }; 若存在一种确定的关系: Kx <= Ky <= … <= Kz则将记录序列 { R1、R2 ……….. Rn } 排成按该关键字有序的序列: { Rx、Ry ……….. Rz } 的操作,称之为排序。
数据结构课程的内容
第10章 内部排序
一、教学内容: 1、插入排序(直接插入排序、折半插入排序、希尔排序); 2、交换排序(起泡排序、快速排序); 3、选择排序(直接选择排序、堆排序); 4、归并排序; 5、基数排序; 二、教学要求: 1、掌握排序的基本概念和各种排序方法的特点,并能加以 灵活应用; 2、掌握插入排序、交换排序、选择排序、归并排序的方法 及其性能分析方法; 3、了解基数排序方法及其性能分析方法。
10 04
76 04 76 76 97
算法分析:开始时dk 的值较大,子序列中的对象较少,排序速度 较快;随着排序进展,dk 值逐渐变小,子序列中对象个数 逐渐变多,由于前面工作的基础,大多数对象已基本有序, 所以排序速度仍然很快。
时间效率: O(n1.25)~O(1.6n1.25)——经验公式 空间效率:O(1)——因为仅占用1个缓冲单元 算法的稳定性:不稳定——因为49*排序后却到了49的前面
优点:让关键字值小的元素能很快前移,且序列若基本
有序时,再用直接插入排序处理,时间效率会高很多。
数据结构.第10章.排序.1.插入排序和交换排序.pptx
排序过程:
i =6
13 13 38 49 65
7趟 76 97个有序子序列,
i =7
27 13 27 38 49 65 76 97 49
然后从第 2 个记录开始,逐个进行插入,直至整个序列有序。
i =8
49 13 27 38 49 49 65 76 97
§10.2 插入排序
❖直接插入排序
void InsertSort ( SqList &L ) { // 对顺序表 L 作直接插入排序。 for ( i = 2; i <= L.length; ++ i )
if (L.r[i].key < L.r[i -1].key) { 在L.rr[0[1].=. i-L1.]r中[i];查找 r[i]//的复插制入为位监置视;哨 对L.r于[i]在=查L.找r[i过-1程]; 中找到的那些关键字 不for小( 于j =ri[-i]2.k;eLy.r的[0记].k录ey,<在L.查r[ j找].的key同; - - j ) 时实L.r现[ j记+录1]向= 后L.r移[ j动];; // 记录后移 插L.r入[ j r+[i1] ]; = L.r[0]; // 插入到正确位置
§10.1 概述
❖概述
内部排序和外部排序 若整个排序过程不需要访问外存便能完成,
则称此类排序问题为内部排序; 反之,若参加排序的记录数量很大,整个序
列的排序过程不可能在内存中完成,则称此类排 序问题为外部排序。
§10.2 插入排序 ❖插入排序
直接插入排序
R0 初始状态
R1 R2 R3
49 38 65
❖概述
排序:将数据元素的一个任意序列,重新排列成 一个按关键字有序的序列。
数据结构第10章内部排序
直接插入排序算法描述如下: void InserSort ( SqList &L) { // 对顺序表L作直接插入排序。 for ( i=2; i<=L.length; ++i ) if (LT(L.r[i].key ,L.r[i-1].key)) { L.r[0] = L.r[i]; // 复制为监视哨 for ( j=i-1; LT(L.r[i].key ,L.r[i-1].key) ; --j ) L.r[j+1] = L.r[j]; // 记录后移 L.r[j+1] = L.r[0]; // 插入到正确位置 } } // InsertSort
空间效率: O(1)
当待排序记录的数量n很小时,直接插入排序是一种简便的方法;但当记录数量n很大时,则不宜采用直接插入排序。
时间效率:虽然比较次数大大减少,可惜移动次数并未减少,所以排序效率仍为O(n2) 。
稳定性:稳定
由于插入排序的基本操作是在有序表R[1..i-1]中进行查找和插入的;则可以利用折半查找实现“在R[1..i-1]中查找R[i]的插入位置”,并在适当位置插入,把原来位置上的元素向后顺移。如此实现的插入排序为折半插入排序。
38
例:关键字序列 T=(49,38,65,97, 76, 13, 27, 49*,55, 04),请写出希尔排序的具体实现过程。
0
1
2
3
4
5
6
7
8
9
10
49
38
65
97
76
13
27
49*
55
04
初态:
第1趟 (dk=5)
第2趟 (dk=3)
第3趟 (dk=1)
中南大学数据结构与算法第10章内部排序课后作业答案要点
第10章内部排序习题练习答案1.以关键字序列(265,301,751,129,937,863,742,694,076,438)为例,分别写出执行以下排序算法的各趟排序结束时,关键字序列的状态。
(1) 直接插入排序(2)希尔排序(3)冒泡排序(4)快速排序(5) 直接选择排序(6) 堆排序(7) 归并排序(8)基数排序上述方法中,哪些是稳定的排序?哪些是非稳定的排序?对不稳定的排序试举出一个不稳定的实例。
答:(1)直接插入排序:(方括号表示无序区)初始态: 265[301 751 129 937 863 742 694 076 438]第一趟:265 301[751 129 937 863 742 694 076 438]第二趟:265 301 751[129 937 863 742 694 076 438]第三趟:129 265 301 751[937 863 742 694 076 438]第四趟:129 265 301 751 937[863 742 694 076 438]第五趟:129 265 301 751 863 937[742 694 076 438]第六趟:129 265 301 742 751 863 937[694 076 438]第七趟:129 265 301 694 742 751 863 937[076 438]第八趟:076 129 265 301 694 742 751 863 937[438]第九趟:076 129 265 301 438 694 742 751 863 937(2)希尔排序(增量为5,3,1)初始态: 265 301 751 129 937 863 742 694 076 438第一趟:265 301 694 076 438 863 742 751 129 937第二趟:076 301 129 265 438 694 742 751 863 937第三趟:076 129 265 301 438 694 742 751 863 937(3)冒泡排序(方括号为无序区)初始态[265 301 751 129 937 863 742 694 076 438]第一趟:076 [265 301 751 129 937 863 742 694 438]第二趟:076 129 [265 301 751 438 937 863 742 694]第三趟:076 129 265 [301 438 694 751 937 863 742]第四趟:076 129 265 301 [438 694 742 751 937 863]第五趟:076 129 265 301 438 [694 742 751 863 937]第六趟:076 129 265 301 438 694 742 751 863 937(4)快速排序:(方括号表示无序区,层表示对应的递归树的层数)初始态:[265 301 751 129 937 863 742 694 076 438]第二层:[076 129] 265 [751 937 863 742 694 301 438] 第三层:076 [129] 265 [438 301 694 742] 751 [863 937] 第四层:076 129 265 [301] 438 [694 742] 751 863 [937] 第五层:076 129 265 301 438 694 [742] 751 863 937第六层:076 129 265 301 438 694 742 751 863 937 (5)直接选择排序:(方括号为无序区)初始态[265 301 751 129 937 863 742 694 076 438]第一趟:076 [301 751 129 937 863 742 694 265 438]第二趟:076 129 [751 301 937 863 742 694 265 438]第三趟:076 129 265[ 301 937 863 742 694 751 438]第四趟:076 129 265 301 [937 863 742 694 751 438]第五趟:076 129 265 301 438 [863 742 694 751 937]第六趟:076 129 265 301 438 694 [742 751 863 937]第七趟:076 129 265 301 438 694 742 [751 863 937]第八趟:076 129 265 301 438 694 742 751 [937 863]第九趟:076 129 265 301 438 694 742 751 863 937(6)堆排序:(通过画二叉树可以一步步得出排序结果)初始态[265 301 751 129 937 863 742 694 076 438]建立初始堆:[937 694 863 265 438 751 742 129 075 301]第一次排序重建堆:[863 694 751 765 438 301 742 129 075] 937第二次排序重建堆:[751 694 742 265 438 301 075 129] 863 937第三次排序重建堆:[742 694 301 265 438 129 075] 751 863 937第四次排序重建堆:[694 438 301 265 075 129] 742 751 863 937第五次排序重建堆:[438 265 301 129 075] 694 742 751 863 937第六次排序重建堆:[301 265 075 129] 438 694 742 751 863 937第七次排序重建堆:[265 129 075] 301 438 694 742 751 863 937第八次排序重建堆:[129 075]265 301 438 694 742 751 863 937第九次排序重建堆:075 129 265 301 438 694 742 751 863 937(7)归并排序(为了表示方便,采用自底向上的归并,方括号为有序区)初始态:[265] [301] [751] [129] [937] [863] [742] [694] [076] [438]第一趟:[265 301] [129 751] [863 937] [694 742] [076 438]第二趟:[129 265 301 751] [694 742 863 937] [076 438]第三趟:[129 265 301 694 742 751 863 937] [076 438]第四趟:[076 129 265 301 438 694 742 751 863 937](8)基数排序(方括号内表示一个箱子共有10个箱子,箱号从0到9)初始态:265 301 751 129 937 863 742 694 076 438第一趟:[] [301 751] [742] [863] [694] [265] [076] [937] [438] [129]第二趟:[301] [] [129] [937 438] [742] [751] [863 265] [076] [] [694]第三趟:[075] [129] [265] [301] [438] [] [694] [742 751] [863] [937]在上面的排序方法中,直接插入排序、冒泡排序、归并排序和基数排序是稳定的,其他排序算法均是不稳定的,现举实例如下:以带*号的表示区别。
数据结构 第十章-排序
43 ) 89 15 43 28 43 89 ) 15 43 28 21 43 89 ) 43 28 21 43 43 89 ) 28 21 28 43 43 89)
直接插入排序算法
void InsertSort(RecType r[],int n)
ቤተ መጻሕፍቲ ባይዱ
// 对数组r[1..n]中的n个记录作插入排序
数据结构 第十章-排序
第十章 内部排序
10.1 概述 1.排序----将文件或表中的记录,通过某种方法整理成按关
键字大小次序排列的处理过程。 假定n个记录的文件为
(R1,R2,...,Rn) 对应的关键字为
(K1,K2,...,Kn) 则排序是确定如下一个排列
p1,p2,...,pn 使得: Kp1≤Kp2≤...≤ Kpn 从而得到一个有序文件
注: 希尔排序是一个不稳定的排序方法。
10.3 交换排序
10.3.1 冒泡排序 基本思想: 设待排序的文件为r[1..n] 第1趟(遍):从r[1]开始,依次比较两个相邻记录的关键字 r[i].key和r[i+1].key,若r[i].key>r[i+1].key,则交换记录 r[i]和r[i+1]的位置;否则,不交换。(i=1,2,...n-1)
Donald Ervin Knuth 高德纳 (1938- ) 斯坦福大学教授
1974年图灵奖得主
《计算机程序设计的艺术》 The Art of Computer Programming 第一卷:基本算法 1968 第二卷:半数字化算法 1969 第三卷:排序与搜索 1973 第四卷:组合算法
《计算机与排版》TEX排版软件
{ // 在r[low..high]中折半查找有序插入的位置
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
第10章排序一、选择题1.某内排序方法的稳定性是指( )。
【南京理工大学 1997 一、10(2分)】A.该排序算法不允许有相同的关键字记录 B.该排序算法允许有相同的关键字记录C.平均时间为0(n log n)的排序方法 D.以上都不对2.下面给出的四种排序法中( )排序法是不稳定性排序法。
【北京航空航天大学 1999 一、10 (2分)】A. 插入B. 冒泡C. 二路归并D. 堆积3.下列排序算法中,其中()是稳定的。
【福州大学 1998 一、3 (2分)】A. 堆排序,冒泡排序B. 快速排序,堆排序C. 直接选择排序,归并排序D. 归并排序,冒泡排序4.稳定的排序方法是()【北方交通大学 2000 二、3(2分)】A.直接插入排序和快速排序 B.折半插入排序和起泡排序C.简单选择排序和四路归并排序 D.树形选择排序和shell排序5.下列排序方法中,哪一个是稳定的排序方法?()【北方交通大学 2001 一、8(2分)】A.直接选择排序 B.二分法插入排序 C.希尔排序 D.快速排序6.若要求尽可能快地对序列进行稳定的排序,则应选(A.快速排序 B.归并排序 C.冒泡排序)。
【北京邮电大学 2001 一、5(2分)】7.如果待排序序列中两个数据元素具有相同的值,在排序前后它们的相互位置发生颠倒,则称该排序算法是不稳定的。
()就是不稳定的排序方法。
【清华大学 1998 一、3 (2分)】A.起泡排序 B.归并排序 C.Shell排序 D.直接插入排序 E.简单选择排序8.若要求排序是稳定的,且关键字为实数,则在下列排序方法中应选()排序为宜。
A.直接插入 B.直接选择 C.堆 D.快速 E.基数【中科院计算所 2000 一、5(2分)】9.若需在O(nlog2n)的时间内完成对数组的排序,且要求排序是稳定的,则可选择的排序方法是()。
A. 快速排序B. 堆排序C. 归并排序D. 直接插入排序【中国科技大学 1998 二、4(2分)】【中科院计算所 1998 二、4(2分)】10.下面的排序算法中,不稳定的是()【北京工业大学 1999 一、2 (2分)】A.起泡排序B.折半插入排序C.简单选择排序D.希尔排序E.基数排序F.堆排序。
11.下列内部排序算法中:【北京工业大学 2000 一、1 (10分每问2分)】A.快速排序 B.直接插入排序 C. 二路归并排序 D. 简单选择排序 E. 起泡排序F. 堆排序(1)其比较次数与序列初态无关的算法是()(2)不稳定的排序算法是()(3)在初始序列已基本有序(除去n个元素中的某k个元素后即呈有序,k<<n)的情况下,排序效率最高的算法是()(4)排序的平均时间复杂度为O(n•logn)的算法是()为O(n•n)的算法是()12.排序趟数与序列的原始状态有关的排序方法是( )排序法。
【北京航空航天大学 1999 一、9(2分)】A.插入 B. 选择 C. 冒泡 D. 快速13.下面给出的四种排序方法中,排序过程中的比较次数与排序方法无关的是。
( ) A.选择排序法 B. 插入排序法 C. 快速排序法 D. 堆积排序法【北京航空航天大学 2000 一、10(2分)】14.对下列四种排序方法,在排序中关键字比较次数同记录初始排列无关的是( )。
A.直接插入 B. 二分法插入 C. 快速排序 D. 归并排序【南京理工大学 2000 一、7 (1.5分)】15.在下列排序算法中,哪一个算法的时间复杂度与初始排序无关()。
【北京理工大学 2001 六、4 (2)】A.直接插入排序 B. 气泡排序 C. 快速排序 D. 直接选择排序16.比较次数与排序的初始状态无关的排序方法是( )。
【北方交通大学 2000 二、2(2分)】A.直接插入排序 B.起泡排序 C.快速排序 D.简单选择排序17.数据序列(8,9,10,4,5,6,20,1,2)只能是下列排序算法中的( )的两趟排序后的结果。
A.选择排序 B.冒泡排序 C.插入排序 D.堆排序【合肥工业大学 1999 一、3 (2分)】18.数据序列(2,1,4,9,8,10,6,20)只能是下列排序算法中的( )的两趟排序后的结果。
A. 快速排序B. 冒泡排序C. 选择排序D. 插入排序【合肥工业大学 2000 一、3 (2分)】19.对一组数据(84,47,25,15,21)排序,数据的排列次序在排序的过程中的变化为(1) 84 47 25 15 21 (2) 15 47 25 84 21 (3) 15 21 25 84 47 (4) 15 21 25 47 84则采用的排序是 ( )。
【南京理工大学 1997 一、2 (2分)】A. 选择B. 冒泡C. 快速D. 插入20.对序列{15,9,7,8,20,-1,4}进行排序,进行一趟后数据的排列变为{4,9,-1,8,20,7,15};则采用的是()排序。
【南京理工大学 1998 一、8(2分)】A. 选择B. 快速C. 希尔D. 冒泡21.若上题的数据经一趟排序后的排列为{9,15,7,8,20,-1,4},则采用的是()排序。
A.选择 B. 堆 C. 直接插入 D. 冒泡【南京理工大学 1998 一、9(2分)】22.下列排序算法中( )不能保证每趟排序至少能将一个元素放到其最终的位置上。
A.快速排序B. shell排序C. 堆排序D.冒泡排序【合肥工业大学 2001 一、3(2分)】23.下列排序算法中( )排序在一趟结束后不一定能选出一个元素放在其最终位置上。
A. 选择B. 冒泡C. 归并D. 堆【南京理工大学 2001 一、7(1.5分)】【哈尔滨工业大学 2001 二、4(2分)】24.下列序列中,()是执行第一趟快速排序后所得的序列。
【福州大学 1998 一、9 (2分)】A. [68,11,18,69] [23,93,73]B. [68,11,69,23] [18,93,73]C. [93,73] [68,11,69,23,18]D. [68,11,69,23,18] [93,73] 25.有一组数据(15,9,7,8,20,-1,7,4)用快速排序的划分方法进行一趟划分后数据的排序为 ( )(按递增序)。
【南京理工大学 1996 一、4 (2分)】A.下面的B,C,D都不对。
B.9,7,8,4,-1,7,15,20C.20,15,8,9,7,-1,4,7 D. 9,4,7,8,7,-1,15,2026.一组记录的关键码为(46,79,56,38,40,84),则利用快速排序的方法,以第一个记录为基准得到的一次划分结果为()。
【燕山大学 2001 一、4(2分)】A.(38,40,46,56,79,84) B. (40,38,46,79,56,84)C.(40,38,46,56,79,84) D. (40,38,46,84,56,79)27. 在下面的排序方法中,辅助空间为O(n)的是( ) 。
【南京理工大学 1999 一、17(1分)】A.希尔排序 B. 堆排序 C. 选择排序 D. 归并排序28.下列排序算法中,在待排序数据已有序时,花费时间反而最多的是( )排序。
A.冒泡 B. 希尔 C. 快速 D. 堆【南京理工大学 2001 一、12 (1.5分)】29.下列排序算法中,在每一趟都能选出一个元素放到其最终位置上,并且其时间性能受数据初始特性影响的是:()。
A. 直接插入排序B. 快速排序C. 直接选择排序D. 堆排序30. 对初始状态为递增序列的表按递增顺序排序,最省时间的是()算法,最费时间的是()算法。
A. 堆排序B. 快速排序C. 插入排序D. 归并排序【南开大学 2000一、5】31. 就平均性能而言,目前最好的内排序方法是( )排序法。
【西安电子科技大学 1998一、9 (2分)】A. 冒泡B. 希尔插入C. 交换D. 快速32.如果只想得到1000个元素组成的序列中第5个最小元素之前的部分排序的序列,用()方法最快。
A.起泡排序 B.快速排列 C.Shell排序 D.堆排序 E.简单选择排序【清华大学 1998 一、2 (2分)】类似本题的另外叙述有:(1)设有5000个无序的元素,希望用最快的速度挑选出其中前十个最大的元素,在以下的排序方法中( )最好?为什么? 【山东工业大学 1995 二、4 (3分)】A.快速排序 B.堆排序 C.归并排序 D.基数排序 E.SHELL排序(2)数据表中有10000个元素,如果仅要求求出其中最大的10个元素,则采用( )算法最节省时间。
A. 堆排序B. 希尔排序C. 快速排序D. 直接选择排序【北京理工大学 2000 一、5 (2分)】(3)设有1000个无序的元素,希望用最快的速度挑选出其中前十个最大的元素,在以下的排序方法中采用哪一种最好? ( ) 【东北大学 1999 一、5 (3分)】A. 快速排序B. 归并排序C. 堆排序D.基数排序E.shell排序33.在文件“局部有序”或文件长度较小的情况下,最佳内部排序的方法是()A.直接插入排序 B.冒泡排序 C.简单选择排序【山东工业大学 1995 二、1 (2分)】类似本题的另外叙述有:(1)在文件"局部有序"或文件长度较小的情况下,最佳内部排序的方法是()。
A. 直接插入排序B. 冒泡排序C. 简单选择排序D. 快速排序【山东大学 2001 二、2 (1分)】(2)在待排序的元素序列基本有序的前提下,效率最高的排序方法是()。
【武汉大学2000 二、6】A.插入排序B. 选择排序C. 快速排序D. 归并排序34.下列排序算法中,()算法可能会出现下面情况:在最后一趟开始之前,所有元素都不在其最终的位置上。
【南开大学 2000 一、4】【西北大学 2001 二、1】A. 堆排序B. 冒泡排序C. 快速排序D. 插入排序35. 下列排序算法中,占用辅助空间最多的是:( ) 【厦门大学 2002 五、2 (8分)】A. 归并排序B. 快速排序C. 希尔排序D. 堆排序36.从未排序序列中依次取出一个元素与已排序序列中的元素依次进行比较,然后将其放在已排序序列的合适位置,该排序方法称为( )排序法。
【北京航空航天大学 1999 一、8(2分)】A. 插入B. 选择C. 希尔D. 二路归并37. 在排序算法中,每次从未排序的记录中挑出最小(或最大)关键码字的记录,加入到已排序记录的末尾,该排序方法是()。
【中山大学 1999 一、11】A. 选择B. 冒泡C. 插入D. 堆38.用直接插入排序方法对下面四个序列进行排序(由小到大),元素比较次数最少的是()。