数据结构——排序

目录

排序:

一.简单选择排序

二.直接插入排序

三.希尔排序

四.冒泡排序

五.快速排序

六.归并排序

七.堆排序

八.基数排序

九.小结:



排序:

将一组任意顺序的数据元素或记录,按照其关键字排列成递增或递减的新序列的操作过程。

一.简单选择排序

基本思路:每次从待排序的序列中选取关键字最小的记录,与当前排序序列的第一个记录交换位置,直到整个序列有序为止。

例:将582461按升序排序。

排序

趟数

1

2

3

4

5

6

初始

5

8

2

4

6

1

1

1

8

2

4

6

5

2

1

2

8

4

6

5

3

1

2

4

8

6

5

4

1

2

4

5

6

8

5

1

2

4

5

6

8

过程说明

一.排序1趟数过程说明:

首先将关键字一(5)关键字二(8)比较大小,关键字一小,再将关键字一(5)关键字三(2)比较大小,关键字三(2)小,再把关键字三与后面的关键字进行比较,最后把数值最小的关键字与关键字一交换数字,结果如排序趟数1所示。

排序2趟数过程说明:

二.经过趟数1的排序,关键字一的数值已经是最小的,所以从关键字二(8)开始排序;

关键字二(8)与后序的关键字进行比较大小,将后序最小值的关键字与关键字二的数值交换位置。结果如趟数2所示:数值2为最小值,将数值2与数值8进行了交换位置。

三.趟数三的过程说明:

与上面的排序过程相同,前两个关键字的大小已经确定了,将关键字三(8)与后序全部的关键字进行比较大小,将最小值与关键字三(8)的位置进行互换。

四.

后序的排序同上述一样。最后结果如趟数5所示。

五.代码

   void SelectSort(SqList *L)
   {                /*对顺序表L作简单选择排序*/
      RecordType  temp;
      for(i=1; i<L->length; ++i)
      {                      /*选择第i个小的记录,并交换到位*/
         j=i;   	          	               /* j用于记录最小元素的位置*/
         for(k=i+1; k<=L->length; k++)     /*在L.r[i..L.length]中选择key最小的记录*/
           if(L->r[k].key<L->r[j].key)     //遍历i后面的所有数,选择最小的数 
		    j=k;                           //用j记录较小的那个数 
           
             if(i!=j)                  /*第i个小的记录L->r[j]与第i个记录交换*/
            {  temp=L->r[j];			//temp此时记录了较小的数 
               L->r[j]=L->r[i];        //把较大的数赋值给后面的那个数 
               L->r[i]=temp;           //较小的赋值给i 
            }  
     } 
  }/*SelectSort

六.算法评价


二.直接插入排序

将一条待排序得记录按照其关键字的大小插入到已经有序的记录中,直到所有记录插入完成并且成为一个有序序列为止。

例:将 8594365* 按升序排序。

待插入元素位置序号

排序

趟数

R[0]

R[1]

R[2]

R[3]

R[4]

R[5]

R[6]

R[7]

初始

8

5

9

4

3

6

5*

i=2

1

5

5

8

9

4

3

6

5*

i=3

2

9

5

8

9

4

3

6

5*

i=4

3

4

4

5

8

9

3

6

5*

i=5

4

3

3

4

5

8

9

6

5*

i=6

5

6

3

4

5

6

8

9

5*

i=7

6

5*

3

4

5

5*

6

8

9

过程说明:

第一趟过程:

首先将R[2]赋值给R[0],然后把R[0]的值与R[1]进行比较,R[0]<R[1],将R[2]的值与R[1]交换,完成第一趟排序。

第二趟排序:

将R[3]的值赋值给R[0],将R[0]的值与前两个值进行比较,R[0]>R[2],所以R[3]>R[2]排列顺序不变。

第三趟排序:

将R[4]的值赋值给R[0],R[0]与前三个值进行,首先从R[1]进行比较,R[0]

<R[1],所以R[1]后面的值往后移动,R[0]的值赋值给[1];

第四趟排序:

将R[5]的值赋值给R[0],然后从R[0]开始依次比较大小,R[0]<R[1],所以R[1]以后的值都往后移动,将R[5]的移动到[1]的位置。

后序的排序方法重复以上操作。

代码

  void InsertSort(SqList *L)
   {       /*对顺序表L作插入排序*/
     for(i=2; i<=L->length; ++i)  //首先用第二个开始,与第一个数r[1]比较 
       if(L->r[i].key<L->r[i-1].key)     //小于前一个数 
       {      /*当“<”时,才需将L->r[i]插入有序表*/
          L->r[0]=L->r[i];                  /*将待插入记录复制为哨兵    r[0]此时是较小的那个数*/
          j=i-1;                            //j为i的前一个数 
         while(L->r[0].key<L->r[j].key)    //哨兵小于j的值 
          {  L->r[j+1]=L->r[j];           /*把大的那个值赋值给后面的位置*/
             j--;                                                  
         }
         //循环后,经j--后,j的位置移动到了j的前一个位置,所以下面需要j++,把j恢复到原来的位置。 
         L->r[j+1]=L->r[0];             /*插入到正确位置*/
      } /* if */
  } /* InsertPass */
 

算法分析


三.希尔排序

基本思路

将整个待排序记录序列分割成若干子序列,对每个子序列进行直接插入排序,待整个序列中纪录“基本有序”时,再对全体记录进行一次直接插入排序。

具体操作:

选择一个增量序列T1......Tn,增序列是一个递减序列,且最后一个增量一定是1,即Tn=1;

按照增量序列个数n,进行n趟排序。

例:对关键字序列 T=(49386597, 76, 13, 27, 49*55,  04)对应的记录进行希尔排序。

表格
r[i]012345678910
初态:4938659776132749*5504
第一趟(t=5)132749*55044938659776
第二趟(t=3)130449*38274955659776
第三趟(t=1)0413273849*4955657697

过程说明

增量序列t=5时,具体分组情况为:49,13;38,27;65,49*;97,55;76,04;

将上述每个小组的数据进行直接插入排序,结果得到第一趟的排序结果。

增量序列t=3时,具体分组情况为:13,38;04,27;49*,49;38,55;27,65;49,97;55,76;

将上述每个小组中的数据进行直接插入排序,结果得到第二趟的排序结果。

第三趟的分组结果:13,04;04,49*;49*,38;38,27;27,49;49,55;55,65;

65,76;76,97;各个小组的直接插入排序同步进行,然后把各个小组的排序结果整合在一起。结果就得出第三趟的排序结果。

代码

   void  ShellInsert(SqList *L, int  delta)
   {     /*对L->r[ ]做一趟希尔插入排序,delta为增量*/
       for(i=1+delta; i <= L->length; i++)         /* 1+delta为第一个子序列的第二个元素的下标*/
        if(L->r[i].key < L->r[i-delta].key)
        {   L->r[0] = L->r[i];        	             /*备份r[i] */
            for(j = i-delta; j > 0&&L->r[0].key < L->r[j].key; j-=delta)
                L->r[j+delta] = L->r[j]; 
                L->r[j+delta] = L->r[0]; 
        }
        
  }
      void  ShellSort(SqList *L)
      /*对记录数组r做希尔排序,delta[0..t-1]为增量序列数组*/
     {      for(i=0; i<t; ++i)  
             ShellInsert(L,delta[i]); 
     } 

算法分析


四.冒泡排序

基本思路

依次将待排序的记录相邻的关键字两两进行比较,如果后面的关键字小于前面的关键字的值,则进行交换记录的位置,没趟排序结束都会确定一个最大值在最后的位置。

例:使用冒泡排序方法将9524按升序排序。

第一趟:

第二趟:

第三趟:

代码

   void BubbleSort(SqList  *L)
   {        /*对记录数组L->r做冒泡排序*/
     RecordType temp;
     n=L->length;   
     change=TRUE;              	/*设置交换标识为TRUE,便于进入循环*/
     for(i=1; i<=n-1&&change; ++i) 
    {  change=FALSE;    	/*在第i趟中先设置记录交换标识为FALSE */  
        for(j=1; j<=n-i; ++j)
          if(L->r[j].key > L->r[j+1].key)     /*若相邻两记录逆序,交换 大的数字与下面小的数字互换位置*/
         {     temp = L->r[j];                //依次执行冒泡原则,先是12比较 ;再23 ;之后34比较。。。。 ; 如此循环     ;把大的那个数,向下排序 ; 
                L->r[j] = L->r[j+1];
                L->r[j+1] = temp;
                change = TRUE; 				//第一次循环结束,true进入下一次循环 
         }
     }
  } /* BubbleSort */
//当i=1;进入第一次循环嵌套,j=1;对顶部的数进行冒泡排序,第一个数到达底部;
//当i=2;进入第二次循环嵌套,j=1; 同时i=2;(第一次循环后,已经有一个数排序完成,所以只需要比较n-i次)继续对顶部的数进行冒泡排序。。。; 
//剩下最后一个数,不需要进行排序,已经是有序的; 

算法分析


五.快速排序

基本思路:

先从数列中选取一个数作为基数(该记录称为枢轴)。

2.将比基准大的数全部放到它的右边,小于或等于基准数的全放到它的左边。

3.再对左右两部分分重复第二步,直到各个区间只有一个数,达到整个序列有序。

轴元素的选取:

通常选取序列中的第一个元素,

选取原则:

1.首元素R[s]或者尾元素R[t]。

2.中值元素,取的是首元素,尾元素,中间位置元素三者中“中间大小”的元素。

3.随机元素R[i],i是s~t之间的一个随机整数。

例题:

第一趟排序结束

 第一趟排序详解

                这里统一选取最左边的数为枢轴元素,以把49取出作为基准,左边low位置为空,所以这里先从high位置开始排序,49*=49,所以49*位置不动,默认如果当前位置未移动,则当前下标继续移动,所以high移动到27的位置,27<49,移动到low的位置。low与high交替移动,所以此时移动low的位置,low移动到38的位置,38<49,不需要移动,此时继续移动low的位置,low移动到65的位置,65>49,所以把65移动到high的位置。这时,移动high的位置,high移动到13的位置,13<49所以把13移动到low的位置,(交替移动位置)所以移动low的位置到97,97>49,所以移动到high的位置,接下来移动high的位置到76,76>49,所以不移动。此时再移动high位置,high位置与low位置重合,此时把基准数填入当前位置。

第一趟排序结束。


第二趟排序结束

第二趟排序详解

经过第一趟排序,数组被分为两部分;49左边为都小于49的数,49右边为都大于49的数。

再分别对这两部分数进行快速排序。

首先对左部分进行排序。

选取左部分数组中,最左边的数作为基准,high位于13的位置,13<27,所以移动到low的位置,此时移动low的位置,38大于27,把38移动到high的位置。再移动high的位置,此时high的位置与low的位置重合,把27填入此时的位置。 

这时,27左右两边的数组分别只有一个数(默认为有序),所以左部分数组排序结束。


第三趟排序结束

第三趟排序详解

同样选取最左边的数作为基准数,然后按照以上原理进行移动。


第四趟排序结束

第四趟排序详解:

第三趟排序后,76把右部分数组分为两部分,做部分有两个数,所以还需要进行排序,选取最左边的数作为基准,high位于65的位置,65大于49,所以不需要进行排序,此时继续移动high的位置,high与low重合,所以填入基准数,排序结束。

代码

   void QSort(RecordType R[], int s, int t)
   {     /*对记录序列R[s..t]进行快速排序*/
      if(s<t-1)          /*长度大于1 */
     {    pivotloc=Partition(R, s, t);  	/*对R[s..t]进行一次划分,并返回枢轴位置*/ 
         QSort(R, s, pivotloc-1);    	/*对低端子序列递归排序*/
           QSort(R, pivotloc+1, t);    	/*对高端子序列递归排序*/
      }//if
  }//Qsort
 

算法分析


六.归并排序

七.堆排序

八.基数排序

九.小结:


后序内容持续完善更新。。。。。。。。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值