排序.docx

上传人:b****3 文档编号:12913698 上传时间:2023-04-22 格式:DOCX 页数:18 大小:22.73KB
下载 相关 举报
排序.docx_第1页
第1页 / 共18页
排序.docx_第2页
第2页 / 共18页
排序.docx_第3页
第3页 / 共18页
排序.docx_第4页
第4页 / 共18页
排序.docx_第5页
第5页 / 共18页
点击查看更多>>
下载资源
资源描述

排序.docx

《排序.docx》由会员分享,可在线阅读,更多相关《排序.docx(18页珍藏版)》请在冰豆网上搜索。

排序.docx

排序

(1)“冒泡法”

冒泡法大家都较熟悉。

其原理为从a[0]开始,依次将其和后面的元素比较,若a[0]>a,则交换它们,一直比较到a[n]。

同理对a[1],a[2],...a[n-1]处理,即完成排序。

下面列出其代码:

C/C++code

voidbubble(int*a,intn)/*定义两个参数:

数组首地址与数组大小*/

{

inti,j,temp;

for(i=0;i

{

for(j=0;j

{

if(a[j]>a[j+1])

{

temp=a[j];

a[j]=a[j+1];

a[j+1]=temp;

}

}

}

}

冒泡法原理简单,但其缺点是交换次数多,效率低。

下面介绍一种源自冒泡法但更有效率的方法“选择法”。

2)“选择法”

选择法循环过程与冒泡法一致,它还定义了记号k=i,然后依次把a[k]同后面元素比较,若a[k]>a[j],则使k=j.最后看看k=i是否还成立,不成立则交换a[k],a,这样就比冒泡法省下许多无用的交换,提高了效率。

C/C++code

voidchoise(int*a,intn)

{

inti,j,k,temp;

for(i=0;i

{

k=i;/*给记号赋值*/

for(j=i+1;j

if(a[k]>a[j])k=j;/*是k总是指向最小元素*/

if(i!

=k)

{/*当k!

=i是才交换,否则a即为最小*/

temp=a[i];

a[i]=a[k];

a[k]=temp;

}

}

}

选择法比冒泡法效率更高,但说到高效率,非“快速法”莫属,现在就让我们来了解它。

(3)“快速法”

快速法定义了三个参数,(数组首地址*a,要排序数组起始元素下标i,要排序数组结束元素下标j).它首先选一个数组元素(一般为a[(i+j)/2],即中间元素)作为参照,把比它小的元素放到它的左边,比它大的放在右边。

然后运用递归,在将它左,右两个子数组排序,最后完成整个数组的排序。

下面分析其代码:

C/C++code

voidquick(int*a,inti,intj)

{

intm,n,temp;

intk;

m=i;

n=j;

k=a[(i+j)/2];/*选取的参照*/

do{

while(a-

while(a[n]>k&&n>i)n--;/*从右到左找比k小的元素*/

if(m<=n){/*若找到且满足条件,则交换*/

temp=a-;

a-=a[n];

a[n]=temp;

m++;

n--;

}

}while(m<=n);

if(m

if(n>i)quick(a,i,n);

}

(4)“插入法”

插入法是一种比较直观的排序方法。

它首先把数组头两个元素排好序,再依次把后面的元素插入适当的位置。

把数组元素插完也就完成了排序。

C/C++code

voidinsert(int*a,intn)

{

inti,j,temp;

for(i=1;i

temp=a;/*temp为要插入的元素*/

j=i-1;

while(j>=0&&temp

a[j+1]=a[j];

j--;

}

a[j+1]=temp;/*插入*/

}

}

二.

直接选择排序 基本思想:

每次从无序数组中选出一个最小的出来,放到已排好序的数组的最后。

 public static void SELECTSORT(int[] R) 

{    

for (int i = 0; i < R.Length-1; i++)     

        int index = i; 

        for (int j = i + 1; j < R.Length; j++) 

        { 

            if (R[j] < R[index]) 

            { 

                index = j;

             }

         } //交换R[i]和R[index] 

         if (index !

= i) 

        { 

            int t = R[i]; R[i] = R[index]; R[index] = t;

         }

     }

  }

插入排序 

基本思想:

首先将数组的第一个数sortArray[0]看成是有序的,然后从第二个元素开始和它前面的元素进行比较,如果比前面的某一个数大,就交换。

由于前面的元素是有序的,所以就使有序元素的个数逐渐增大,直到等于n。

 public void Sort(int[] sortArray) { 

    int j = 0; 

    int key = 0;   // key为哨兵 

    for (int i = 1; i < sortArray.Length; i++)     //[0..i-1]已经排好的有序列     { 

        if (sortArray[i] < sortArray[i - 1])         { 

            key = sortArray[i];             j = i - 1; 

            while (j >= 0 && key < sortArray[j]) //当sortArray[i] ≥sortArray[j] 时终止             {  

                sortArray[j + 1] = sortArray[j];                 j--;             }     

            sortArray[j + 1] = key;  //插入到j的后面         }     } }

冒泡排序 

基本思想:

两两比较待排序的数,发现反序时交换,直到没有反序为止。

 public static void BubbleSort(int[] R) { 

    for (int i = 0; i < R.Length - 1; i++)     { 

        bool noswap = true; 

        for (int j = 0; j < R.Length - 1-i; j++)         { 

            if (R[j] > R[j + 1])             { 

                int temp = R[j];                 R[j] = R[j + 1];                 R[j + 1] = temp;                 noswap = false;             }         } 

        if (noswap)         { 

            break;         }     } }

正版。

直接选择排序(StraightSelectionSort)

1、直接选择排序的基本思想

 n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果:

①初始状态:

无序区为R[1..n],有序区为空。

②第1趟排序

 在无序区R[1..n]中选出关键字最小的记录R[k],将它与无序区的第1个记录R[1]交换,使R[1..1]和R[2..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。

  ……

③第i趟排序

  第i趟排序开始时,当前有序区和无序区分别为R[1..i-1]和R[i..n](1≤i≤n-1)。

该趟排序从当前无序区中选出关键字最小的记录R[k],将它与无序区的第1个记录R[i]交换,使R[1..i]和R[i+1..n]分别变为记录个数增加1个的新有序区和记录个数减少1个的新无序区。

 这样,n个记录的文件的直接选择排序可经过n-1趟直接选择排序得到有序结果。

2、直接选择排序的过程

  对初始关键字为49、38、65、97、76、13、27和49的文件进行直接选择排序的过程【参见动画演示】

3、算法描述

  直接选择排序的具体算法如下:

 voidSelectSort(SeqListR)

 {

inti,j,k;

for(i=1;i

k=i;

for(j=i+1;j<=n;j++)//在当前无序区R[i..n]中选key最小的记录R[k]

if(R[j].key

k=j;//k记下目前找到的最小关键字所在的位置

if(k!

=i){//交换R[i]和R[k]

R[0]=R[i];R[i]=R[k];R[k]=R[0];//R[0]作暂存单元

}//endif

}//endfor

}//SeleetSort

 

/*

冒泡排序基本思想

将n个记录看作按纵向排列,每趟排序时自下至上对每对相邻记录进行比较,若次序不符合要求(逆序)就交换。

每趟排序结束时都能使排序范围内关键字最小的记录象一个气泡一样升到表上端的对应位置,整个排序过程共进行n-1趟,依次将关键字最小、次小、第三小…的各个记录“冒到”表的第一个、第二个、第三个…位置上。

初态第1趟第2趟第3趟第4趟第5趟第6趟第7趟

3812121212121212

2038202020202020

4620382525252525

3846253838383838

7438463838383838

9174384646464646

1291747474747474

2525919191919191*///打印数组voidPrintArray(intarray[],intn)

{inti;for(i=0;i

printf("%d",array[i]);

printf("\n");

}//冒泡排序voidBubbleSort(intarray[],intn)

{inti=0;intj=0;inttemp=0;intflag=0;for(i=0;i

{

flag=0;/*本趟排序开始前,交换标志应为假*/for(j=n-1;j>i;j--)/*内循环控制一趟排序的进行*/

{if(array[j]

{

temp=array[j];

array[j]=array[j-1];

array[j-1]=temp;

flag=1;/*发生了交换,故将交换标志置为真*/

}

}if(flag==0)/*本趟排序未发生交换,提前终止算法*/break;/*

printf("第%d趟排序结果:

\n",i+1);

PrintArray(array,n);*/

}

}

voidTestBubbleSort()

{intarray[8]={38,20,46,38,74,91,12,25};

BubbleSort(array,8);

PrintArray(array,8);

}

 

题外话:

在深入学习更多排序算法后和在实际使用情况中,冒泡排序的使用还是极少的。

它适合数据规模很小的时候,而且它的效率也比较低,但是作为入门的排序算法,还是值得学习的

先尝试用最简单的想法去实现排序,以此来比较学习冒泡排序

问题:

设有一数组,其大小为10个元素(intstr[10])数组内的数据是无序。

现在要求我们通过编程将这个无序的数组变成一个从小到大排序的数组(从下标为0开始)

思路:

按照题目的要求,毫无疑问,正确的结果应该就像这样:

12345678910要做到这样,最简单和最直接想到的方法就是进行对比交换。

∙首先,把10个数里最小的个数放到下标为0的位置上(str[0])

∙通过将下标为0的数(str[0])与剩下其余9个数进行对比交换(将较少者放置在下标为0的位置上),就可以得到这10个数最小的那个

∙10个数最小的那位确定后,接下来就要找剩下9个数最小的那个。

∙因为已经确定出一个最小的数,所以就不要动str[0],直接从str[1]开始,与剩下的8个数对比交换,找出9个数中最小的那位放到下标为1(str[1])的位置上

∙继续按照这个思路就可以将这十个数变成有序的(从小到大)的数组

代码:

[cpp]viewplaincopyprint?

1#include

2

3voidswap(int*a,int*b);//交换两个数

4

5intmain()

6{

7intstr[10];

8inti,j;

9//初始化数组为10987654321

10for(i=0;i<10;i++)

11{

12str[i]=10-i;

13}

14//排序,从a[0]开始排,从小到大

15for(i=0;i<10;i++)

16{

17for(j=i+1;j<10;j++)

18{

19if(str[i]>str[j])

20{

21swap(&str[i],&str[j]);

22}

23}

24}

25//将十个数输出

26for(i=0;i<10;i++)

27printf("%d\n",str[i]);

28return0;

29}

30voidswap(int*a,int*b)

31{

32intc;

33c=*a;

34*a=*b;

35*b=c;

36}

这个方法是比较容易想到的实现方法。

但存在不足:

就是本来位于前面的较小数被交换到后面

演示:

开始:

94568327101(下标从左到右分别是0~9)按照上面的程序进行对比交换

第一次:

49568327101

第二次:

49568327101

(没有交换)

第五次:

39568427101

第六次:

29568347101

(没有交换)

第十次:

19568347102

可以看出,原来较小的数是在前面的,经过一轮的交换后放到后面了

那么怎样解决这个不足呢?

可以使用冒泡排序

什么是冒泡排序呢?

你可以这样理解:

(从小到大排序)存在10个不同大小的气泡,由底至上地把较少的气泡逐步地向上升,这样经过遍历一次后,最小的气泡就会被上升到顶(下标为0),然后再从底至上地这样升,循环直至十个气泡大小有序。

在冒泡排序中,最重要的思想是两两比较,将两者较少的升上去

冒泡排序最坏情况的时间复杂度是O(n²)

代码:

[cpp]viewplaincopyprint?

37#include

38voidswap(int*a,int*b);

39intmain()

40{

41intarray[10]={15,225,34,42,52,6,7856,865,954,10};

42inti,j;

43for(i=0;i<10;i++)

44{

45//每一次由底至上地上升

46for(j=9;j>i;j--)

47{

48if(array[j]

49{

50swap(&array[j],&array[j-1]);

51}

52}

53}

54for(i=0;i<10;i++)

55{

56printf("%d\n",array[i]);

57}

58return0;

59}

60voidswap(int*a,int*b)

61{

62inttemp;

63temp=*a;

64*a=*b;

65*b=temp;

66}

 

一.算法描述

插入排序:

插入即表示将一个新的数据插入到一个有序数组中,并继续保持有序。

例如有一个长度为N的无序数组,进行N-1次的插入即能完成排序;第一次,数组第1个数认为是有序的数组,将数组第二个元素插入仅有1个有序的数组中;第二次,数组前两个元素组成有序的数组,将数组第三个元素插入由两个元素构成的有序数组中......第N-1次,数组前N-1个元素组成有序的数组,将数组的第N个元素插入由N-1个元素构成的有序数组中,则完成了整个插入排序。

以下面5个无序的数据为例:

6527596458(文中仅细化了第四次插入过程)

第1次插入:

2765596458

第2次插入:

2759656458

第3次插入:

2759646558

第4次插入:

2758596465

二.算法分析

平均时间复杂度:

O(n2)

空间复杂度:

O

(1)(用于记录需要插入的数据)

稳定性:

稳定

三.算法实现

从前向后查找的插入排序:

[cpp]viewplaincopy

∙/********************************************************

∙*函数名称:

InsertSort

∙*参数说明:

pDataArray无序数组;

∙*iDataNum为无序数据个数

∙*说明:

插入排序

∙*********************************************************/

∙voidInsertSort(int*pDataArray,intiDataNum)

∙{

∙for(inti=1;i

∙{

∙intj=0;

∙while(j

∙j++;

∙if(j

∙{

∙intk=i;

∙inttemp=pDataArray[i];

∙while(k>j)//挪动位置

∙{

∙pDataArray[k]=pDataArray[k-1];

∙k--;

∙}

∙pDataArray[k]=temp;//插入

∙}

∙}

∙}

但楼主发现从后面查找插入的方式,代码复杂程度较低:

[cpp]viewplaincopy

∙/********************************************************

∙*函数名称:

InsertSort

∙*参数说明:

pDataArray无序数组;

∙*iDataNum为无序数据个数

∙*说明:

插入排序

∙*********************************************************/

∙voidInsertSort(int*pDataArray,intiDataNum)

∙{

∙for(inti=1;i

∙{

∙intj=i-1;

∙inttemp=pDataArray[i];//记录要插入的数据

∙while(j>=0&&pDataArray[j]>temp)//从后向前,找到比其小的数的位置

∙{

∙pDataArray[j+1]=pDataArray[j];//向后挪动

∙j--;

∙}

∙if(j!

=i-1)//存在比其小的数

∙pDataArray[j+1]=temp;

∙}

∙}

四.算法优化

插入排序中,总是先寻找插入位置,然后在实行挪动和插入过程;寻找插入位置采用顺序查找的方式(从前向后或者从后向前),既然需要插入的数组已经是有序的,那么可以采用二分查找方法来寻找插入位置,提高算法效率,但算法的时间复杂度仍为O(n2)。

[cpp]viewplaincopy

∙//查找数值iData在长度为iLen的pDataArray数组中的插入位置

∙intFindInsertIndex(int*pDataArray,intiLen,intiData)

∙{

∙intiBegin=0;

∙intiEnd=iLen-1;

∙intindex=-1;//记录插入位置

∙while(iBegin<=iEnd)

∙{

∙index=(iBegin+iEnd)/2;

∙if(pDataArray[index]>iData)

∙iEnd=index-1;

∙else

∙iBegin=index+1;

∙}

∙if(pDataArray[index]<=iData)

∙index++;

∙returnindex;

∙}

∙/*********************************

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

当前位置:首页 > 教学研究 > 教学反思汇报

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

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