《第9章内部排序》习题解答概论Word文档格式.docx

上传人:b****8 文档编号:22459701 上传时间:2023-02-04 格式:DOCX 页数:28 大小:80.73KB
下载 相关 举报
《第9章内部排序》习题解答概论Word文档格式.docx_第1页
第1页 / 共28页
《第9章内部排序》习题解答概论Word文档格式.docx_第2页
第2页 / 共28页
《第9章内部排序》习题解答概论Word文档格式.docx_第3页
第3页 / 共28页
《第9章内部排序》习题解答概论Word文档格式.docx_第4页
第4页 / 共28页
《第9章内部排序》习题解答概论Word文档格式.docx_第5页
第5页 / 共28页
点击查看更多>>
下载资源
资源描述

《第9章内部排序》习题解答概论Word文档格式.docx

《《第9章内部排序》习题解答概论Word文档格式.docx》由会员分享,可在线阅读,更多相关《《第9章内部排序》习题解答概论Word文档格式.docx(28页珍藏版)》请在冰豆网上搜索。

《第9章内部排序》习题解答概论Word文档格式.docx

i++)cin>

>

A[i];

}

2.数组输出操作

函数voidOutput(intA[],intn)的功能是,依次显示输出数组A[]中的n个整数。

voidOutput(intA[],intn)

结果为:

i++)cout<

A[i]<

"

endl;

3.数组排序操作

函数voidMainSort(void(*sort)(int*,int))的功能是,首先通过函数调用Input(A,n)输入n个整数到数组A[]中,再通过函数调用sort(A,n)对A[]中的n个整数排序,最后通过函数调用Out(A,n)显示输出数组A[]中的n个整数。

voidMainSort(void(*sort)(int*,int))

{int*A,n;

请输入整数的个数:

cin>

A=newint[n];

Input(A,n);

原顺序"

Output(A,n);

sort(A,n);

//调用sort对数组A进行处理

排序后的顺序"

Out(A,n);

delete[]A;

9.2插入排序法

9.2.1直接插入排序(StraightInsertionSort)

1.算法思想

对于任意排列的序列(a0,a1,a2,…,an-1),先将第一个记录看成是一个有序序列L1=(a0),再将第2个记录插入到L1中得到有序序列L2=(a0,a1)

一般的,将第k+1个记录插入到有序序列Lk中得到有序序列Lk+1,如此重复插入n-1次即可得到有序序列Ln=(a0,a1,a2,…,an-1)。

2.举例说明

设原始序列为:

8、3、5、2、9、7、*5、4

第1轮:

(8)3,5,2,9,7,*5,4

第2轮:

(3,8)5,2,9,7,*5,4

第3轮:

(3,5,8)2,9,7,*5,4

第4轮:

(2,3,5,8)9,7,*5,4

第5轮:

(2,3,5,8,9)7,*5,4

第6轮:

(2,3,5,7,8,9)*5,4

第7轮:

(2,3,5,*5,7,8,9)4

第8轮:

(2,3,4,5,*5,7,8,9)

3.算法实现

voidInsertSort(intA[],intn)

{inttemp,i,j;

n-1;

i++)

{for(temp=A[i+1],j=i+1;

j>

0;

j--)

{if(temp>

=A[j-1])break;

A[j]=A[j-1];

}

A[j]=temp;

//将temp插入到相应的位置

}

4.算法分析

从排序过程可知该算法是稳定的;

算法的比较次数为f(n)=1+2+3+…+n-1,所以该算法的时间复杂度为T(n)=O(n2);

由于在排序过程中仅有一个辅助变量(temp),所以该算法的空间复杂度为S(n)=O

(1)。

说明:

(1)从算法的基本操作部分可以看出,当待排序数组A[n]基本有序时可以大大减少其比较的执行次数,所以该算法适用于序列为基本有序的场合。

(2)使用直接插入排序算法排序时可能出现下列情况:

在最后一趟开始之前,所有的元素都不在其最终的位置上。

比如,初始序列的最后一个元素为最小元素时就会出现以上情况。

*9.2.2折半插入排序

折半插入排序是直接插入排序的一个改进算法,该算法在排序过程中,通过折半查找法来实现寻找插入位置的操作,从而减少了数据元素中关键字的比较次数。

1.折半插入排序函数

voidInertSort1(inta[],intn)

{inti,j,k,t,l,h;

for(i=1;

if(a[i]<

a[i-1])

{l=0;

h=i-1;

while(l<

=h)//用二分法查找插入位置

{t=(l+h)/2;

if(a[t]==a[i])break;

elseif(a[t]<

a[i])l=t+1;

elseh=t-1;

}

if(h<

l)t=l;

//查找失败

for(k=a[i],j=i;

t;

j--)a[j]=a[j-1];

a[j]=k;

2.分步实现折半查找插入排序

(1)函数intFound(intA[],intn,intx)通过折半查找法求元素x在数组A[n]中的插入下标。

intFound(intA[],intn,intx)

{intt,l,h;

l=0;

h=n-1;

if(x>

=A[h])t=n;

elseif(x<

=A[0])t=0;

else

{while(l<

=h)

if(A[t]==x)break;

elseif(A[t]<

x)l=t+1;

returnt;

(2)调用函数Found()实现插入排序。

voidInertSort2(inta[],intn)

{inti,j,x,t;

{x=a[i];

t=Found(a,i,x);

for(j=i;

j--)a[j]=a[j-1];

a[t]=x;

9.2.3希尔排序法(ShellSort)

先将整个待排的n个记录序列按照某个间隔值d1(通常取n/2)分割成为若干个子序列,再对其分别进行直接插入排序,下一步取间隔值d2<

d1(通常取di+1=di/2)重复前面的过程

直到间隔值为1时对整体序列进行最后一次直接插入排序。

7、5、9、13、10、2、3、*5、8、1,其长度为n=10。

取间隔值d=10/2=5,先将序列看成如图9.1(a)所示的5个子序列:

(7,2)(5,3)(9,*5)(13,8)(10,1)。

再分别对每个子序列进行插入排序,其结果为如图9.1(b)所示的子序列:

(2,7)(3,5)(*5,9)(8,13)(1,10)。

第1轮排序结果为:

2,3,*5,8,1,7,5,9,13,10(注意:

在对各子序列排序时,子序列在主序列中的相对位置不变)。

取间隔值d=5/2=2,先将序列分成如图9.2(a)所示的2个子序列:

(2,*5,1,5,13)(3,8,7,9,10)。

再分别进行插入排序,其结果为如图9.2(b)所示的子序列:

(1,2,*5,5,13)(3,7,8,9,10)。

第2轮排序结果为:

1,3,2,7,*5,8,5,9,13,10。

取d=2/2=1,此时将整体序列进行一次直接插入排序。

第3轮排序结果为:

1,2,3,*5,5,7,8,9,10,13。

(1)算法Insert(A,k,n)的功能是,对数组A[n]按间隔k进行分组插入排序

voidInsert(intA[],intk,intn)

{inti,j,temp;

for(i=k-1;

{//A[i+1]为要插入的元素

for(temp=A[i+1],j=i+1;

j-k>

=0;

j-=k)

{//在相应的子序列中寻找插入位置。

if(temp>

=A[j-k])break;

A[j]=A[j-k];

A[j]=temp;

(2)希尔排序函数

voidShellSort(intA[],intn)

{intk=n;

while(k=k/2){Insert(A,k,n);

该算法是不稳定的;

希尔排序算法的时间复杂度与间隔值d的取法有关,当取d1=n,di+1=di/2(i=1,2,3,…)时,该算法的时间复杂度为T(n)=O(nlog2n),空间复杂度为S(n)=O

(1)。

9.3交换排序法

交换排序是借助于交换操作来完成的排序方法。

它的基本思想是:

在待排序的序列中,找到不满足序性的两个关键字,交换相应元素的相对位置,以满足序性;

重复该过程,直到序列中所有元素的关键字都有序为止。

本节主要介绍最为常见的两个交换排序算法:

起泡排序法和快速排序法。

9.3.1起泡排序法(BubbleSort)

1.算法思想(大数沉底法)

起泡排序算法的基本思想是:

先将第1个与第2个记录的关键字比较,如果关键字逆序,则交换这两个记录,否则不交换;

再将第2个与第3个记录的关键字比较,如果关键字逆序,则交换第2个与第3个记录,否则不交换,…,以此类推,最后将第n-1个与第n个记录的关键字比较,如果关键字逆序,则交换,否则不交换。

上述过程称为一趟起泡排序,其结果是使关键字值最大的记录移到第n个记录的位置。

然后对前n-1个记录进行同样的操作,第2趟起泡排序的结果是使关键字值次大的记录移到第n-1个记录的位置。

一般地,第i趟起泡排序的结果是从前n-i个记录中将关键字最大的记录移到第n-i+1个记录的位置上。

如果在某一趟排序中没有发生交换操作,则整个排序提前结束,否则最后排到仅剩一个记录为止。

设原始记录序列为:

第1趟排序结果:

3,5,2,8,7,*5,4,(9)

第2趟排序结果:

3,2,5,7,*5,4,(8,9)

第3趟排序结果:

2,3,5,*5,4,(7,8,9)

第4趟排序结果:

2,3,5,4,(*5,7,8,9)

第5趟排序结果:

2,3,4,(5,*5,7,8,9)

第6趟排序结果:

2,3,(4,5,*5,7,8,9)

由于没有发生交换操作,排序提前结束。

voidBubbleSort(intA[],intn)

{inti,j,t,f;

//f=1时表示发生了交换操作

for(f=1,i=n-1;

i>

0&

&

f;

i--)

{for(f=0,j=0;

j<

i;

j++)

if(A[j]>

A[j+1])//如果产生逆序

{f=1;

t=A[j];

A[j]=A[j+1];

A[j+1]=t;

//交换A[j]与A[j+1]的值

起泡排序算法是稳定的。

容易算出,该算法的时间复杂度为T(n)=O(n2),空间复杂度为S(n)=O

(1)。

算法的基本操作是交换操作,如果待排序的数组基本有序,那么可以大量地减少排序过程中的交换操作。

所以,起泡排序算法适用于序列为基本有序的场合。

9.3.2快速排序法(QuickSort)

快速排序算法的基本思想是:

通过一趟排序将待排记录分割成独立的两部分,其中一部分的关键字均比另一部分的关键字小。

接着对独立的每一组记录再分别进行排序和分割,直到每一组中都只有一个记录为止。

2.一趟快速排序的具体做法

附设两个指针low,high,其初值分别指向首个记录和最后一个记录,另设关键字为Key的枢轴记录变量(初始值为Low所指记录)。

首先从High所指记录开始起向前搜索,找到第1个关键字小于Key的记录同时将该记录存储到Low所指记录中,然后从Low所指记录开始向后搜索,找到第1个关键字大于Key的记录存于High所指记录中,再重复以上步骤,直到Low=High为止。

最后将Key中记录存储到Low所指记录中。

3.举例说明

38,13,27,76,65,49,49,97,其初始状态如图9.3所示。

第1趟排序:

27,13,(38),76,65,49,49,97

第2趟排序:

13,(27),(38),76,65,49,49,97

第3趟排序:

13,(27),(38),49,65,49,(76),97

第4趟排序:

13,(27),(38),(49),65,49,(76),97

第5趟排序:

13,(27),(38),(49),49,(65),(76),97

4.快速排序的算法实现

(1)算法intPart(int*H,intlow,inthigh)返回下标值i,使得在数组元素H[low]到H[high]中,H[i]前面的元素均小于等于H[i],H[i]后面的元素均大于等于H[i]。

intPart(int*H,intlow,inthigh)

{

intkey=H[low];

while(low<

high)

{while(low<

high&

H[high]>

=key)high--;

H[low]=H[high];

while(low<

H[low]<

=key)low++;

H[high]=H[low];

H[low]=key;

return(low);

//返回H[low]到H[high]中的枢轴变量下标

(2)函数voidQsort(int*H,intlow,inthigh)功能是,通过递归算法对数组H[]中从H[low]到H[high]的元素进行快速排序。

voidQsort(int*H,intlow,inthigh)//对数组元素H[low]到H[high]进行快速排序

intp;

//p为枢轴变量下标

if(low<

{p=Part(H,low,high);

Qsort(H,low,p-1);

Qsort(H,p+1,high);

voidQuickSort(intA[],intn){Qsort(A,0,n-1);

5.算法分析

快速排序算法是不稳定的,该算法的时间复杂度一般被认为是T(n)=O(nlog2n)中速度最快的排序法。

需要说明的是:

快速排序算法在最坏的情况下(序列为基本有序)将退化为起泡排序算法,其时间复杂度是T(n)=O(n2)。

因此,该算法不适用于序列为基本有序的场合。

9.4选择排序法(Selectionsort)

选择排序算法是另一类常用的排序方法。

选择排序的基本思想是:

第一趟,从n个元素中选取关键字值最小的元素与第一个元素互换;

第二趟,从剩余的n-1个元素中选取关键字值最小的元素与第二个元素互换;

一般地,第i趟,从剩余的n-i+1个元素中选取关键字值最小的元素与第i个元素互换。

重复以上过程,直到剩余元素仅有一个为止。

9.4.1简单选择排序法(SimpleSelectionSort)

1.基本算法思想

简单选择排序的算法思想是:

第一趟,取下标值i=0,下标值j从1到n-1逐个由A[i]与A[j]进行比较,如果A[i]>

A[j]则i=j,最后,如果i!

=0时执行A[0]与A[i]的交换操作;

第二趟,取下标值i=1,下标值j从2到n-1逐个由A[i]与A[j]进行比较,如果A[i]>

=1时执行A[1]与A[i]的交换操作;

重复以上过程n-1次后,对数组A[n]的排序过程结束。

(2),3,5,8,9,7,*5,4

(2,3),5,8,9,7,*5,4

(2,3,4),8,9,7,*5,5

(2,3,4,*5),9,7,8,5

(2,3,4,*5,5),7,8,9

(2,3,4,*5,5,7),8,9

第7趟排序结果:

(2,3,4,*5,5,7,8),9

3.选择排序的算法实现

voidSelectSort(intA[],intn)

{inti,j,k,t;

{for(k=i,j=i+1;

j++)if(A[j]<

A[k])k=j;

//查找最大关键字元素的下标k

if(k!

=i){t=A[i],A[i]=A[k],A[k]=t;

}//A[i]与A[k]交换

4.算法分析:

直接选择排序算法是不稳定的;

该算法的基本操作主要是元素的比较,其比较次数与待排序数组的初始状态无关,比较次数为f(n)=1+2+…+(n-1),时间复杂度为T(n)=O(n2),空间复杂度为S(n)=O

(1)。

9.4.2堆排序法(HeapSort)

堆排序是借助于一种称为堆的结构所进行的排序方法,它仅需要一个元素大小的辅助空间。

1.堆的定义

n个元素序列

当且仅当满足以下关系时称之为堆。

对任意的i=1,2,...,[n/2]满足:

(1)

(2)

当元素序列满足

(1)式的条件时称序列

为小顶堆;

当序列满足

(2)式时称序列

为大顶堆。

事实上,若将此序列对应的一维数组看成是一棵完全二叉树的顺序存储,则堆的含义表明,该二叉树中所有非终端结点的值均不大于(或小于)其左右孩子的值。

2.堆排序

在输出堆顶的最小(最大)值之后,使得剩余n-1个元素序列重又调整成为一个堆,则可得到n-1个元素中的次最小(大)值。

如此反复执行n-1轮后,便能得到一个有序序列,这个过程称之为堆排序。

3.堆排序的算法演示举例

(1)由初始序列构造成一个初始(大顶)堆

假设待排序的初始序列为:

49,38,65,97,76,13,27,49。

其中,n=8,n/2=8/2=4,根据完全二叉树的有关性质可知,其最后一个非叶结点的编号为4(即第4个结点)。

调整成为初始(大顶)堆的过程是,从第4个元素97开始逐个向前进行调整,使它们都满足

(2)式的条件。

第1步:

(4)97>

=(8)49;

(3)65>

=(6)13和(7)27;

自然满足;

如图9.4(a)所示。

第2步:

(2)38>

=(4)97和(5)76不满足,执行操作:

先38与97互换,再38与49互换。

调整后到结果如图9.4(b)所示,其结果为:

(1)49,

(2)97,(3)65,(4)49,(5)76,(6)13,(7)27,(8)38

第3步:

(1)49>

=

(2)97和(3)65不满足,先执行操作49与97互换,再49与76互换,调整结果如图9.4(c)所示。

最终结果为:

(1)97,

(2)76,(3)65,(4)49,(5)49,(6)13,(7)27,(8)38

(2)通过对序列的重复调整进行排序

(1),(8)互换,并将

(1)到(7)的元素调整成为大顶堆,其结果如图9.5(a)所示。

第1步调整的结果为:

(1)76,

(2)49,(3)65,(4)49,(5)38,(6)13,(7)27,97

(1),(7)互换,并将

(1)到(6)的元素调整成为大顶堆,其结果如图9.5(b)所示。

第2步调整的结果为:

(1)65,

(2)49,(3)27,(4)49,(5)38,(6)13,76,97

(1),(6)互换,并将

(1)到(5)的元素调整成为大顶堆,其结果如图9.5(c)所示。

第3步调整的结果为:

(1)49,

(2)49,(3)27,(4)13,(5)38,65,76,97

第4步:

(1),(5)互换,并将

(1)到(4)的元素调整成为大顶堆,其结果如图9.5(d)所示。

第4步调整的结果如为:

(1)49,

(2)38,(3)27,(4)13,49,65,76,97

依此类推,

第5步为:

(1)38,

(2)13,(3)27,49,49,65,76,97;

第6步为:

(1)27,

(2)13,38,49,49,65,76,97;

第7步为:

13,27,38,49,49,65,76,97。

3.堆排序的算法实现

(1)调整为大顶堆

算法voidHeapAdjust(int*H,ints,intm)的功能是,调整序列H中元素,使序列中第s个到第m个元素成为大顶堆。

voidHeapAdjust(int*H,ints,intm)

{intj,t;

t=H[s-1];

j=s*2;

while(j<

=m)//循环中s-1为双亲结点下标,j-1为孩子结点下标,t为要调整的值

{if(j<

m&

H[j-1]<

H[j])j++;

if(t>

=H[j-1])break;

H[s-1]=H[j-1];

s=j;

j=j*2;

H[s-1]=t;

(2)堆排序程序

voidHeapSort(int*H,intn)

{inti,t;

for(i=n/2;

i--)//从最后一个分支结点开始通过循环调用HeapAdjust()构造初始堆

HeapAdjust(H,i,n);

初始堆为:

Output(H,n);

for(i=n-1;

i--)//对初始堆H进行调整的排序过程

{t=H[0];

H[0]=H[i];

H[i]=t;

HeapAdjust(H,1,i);

//调整H中H[0]到H[i

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 高考

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1