10-排序-03-选择排序

来源:互联网 发布:淘宝大图轮播尺寸 编辑:程序博客网 时间:2024/06/06 02:30

1.简单选择排序

基本思想:

(1)初始状态:整个数组 r 划分成两个部分,即有序区(初始为空)和无序区。
(2)基本操作:从无序区中选择关键字值最小的记录,将
其与无序区的第一个记录交换(实质是添加到有序区尾部)。
从初态(有序区为空)开始,重复步骤(2),直到终态

(无序区为空)。

排序过程

    首先通过 n-1 次关键字比较,从n 个记录中找出关

键字最小的记录,将它与第一个记录交换

    再通过 n-2次比较,从剩余的 n-1 个记录中找出关

键字次小的记录,将它与第二个记录交换

    重复上述操作,共进行n-1趟 排序后,排序结束。


算法:

 void Selectsort(){ for (i=1;i<n;i++)  { k=i;     for (j=i+1;j<=n;j++)     if (R[j].key<R[k].key)                  // 选择关键字值最小的记录         k=j;     if ( k!=i )        { R[0]=R[i];           R[i]=R[k];           R[k]=R[0];        }                // 交换记录   }}



效率分析:

         简单选择排序比较次数与关键字初始排序无关。

         找第一个最小记录需进行n-1次比较,找第二个最小记录需要比较n-2次,找第i个最小记录需要进行n-i次比较,总的比较次数为:

       (n-1)+(n-2)+……+(n-i)+……2+1=n(n-1)/2=n2/2

         时间复杂度:O(n2)

         辅助空间:O(1)

         简单选择排序是不稳定的排序方法。

2. 堆排序

堆排序法是利用堆树(Heap Tree)来进行排序的方法,堆树是一种特殊的二叉树,其具备以下特征:
(1)是一棵完全二叉树。
(2)每一个根结点的值均大于或等于它的两个子结点的值。
(3)树根的值是堆树中最大的。


基本思想:

(1)把用数组存储的待排序数据,转换成一棵完全二叉树。
(2)将完全二叉树转换成堆树。
(3)有了堆树后,便可以排序。

例:输入数据序列为:80 13 6 88 27 75 42 69
分析其堆排序的过程。

(1)画出完全二叉树

          位置(i)                    1     2   3    4     5    6     7    8

       一维数组中的数据      80   13  6   88   27  75   42  69

         对于任一位置,若父结点的位置为i则它的两个子结点分别

位于 2i和 2i+1 。根据数组中的数据可画出如图所示的完全二叉树。



(2)建堆过程

1) 从数组中间开始调整。
2) 找出此父结点的两个子结点的较大者,再与父结点比较,若父结点小,则交换。然后以交换后的子结点作为新的父结点,重复此步骤直到没有子结点。
3) 把步骤 2)中原来的父结点的位置往前推一个位置,作为新的父结点。重复步骤 2),直到树根为止。

(3) 实现堆排序:

    堆排序:将无序序列建成一个堆,得到关键字最大(或最小)

的记录;输出堆顶的最大)值后, 使剩余的 n-1个元素重又

建成一个堆,则可得到n 个元素的次大)值;重复执行,得

到一个有序序列。

    实现堆排序要解决的一个问题:

   即输出堆顶元素后,怎样调整剩余的 n-1个元素,使其按关

键码成为一个新堆。 

 调整方法:

   设有m个元素的堆,输出堆顶元素后,剩下m-1个元素。

将堆底元素送入堆顶,堆被破坏,其原因仅是根结点不满

足堆的性质。将根结点与左、右子女中较大的进行交换。

若与左子女交换,则左子树堆被破坏,且仅左子树的根结

点不满足堆的性质;若与右子女交换,则右子树堆被破坏,

且仅右子树的根结点不满足堆的性质。继续对不满足堆性

质的子树进行上述交换操作,直到叶子结点,堆被建成

称这个自根结点到叶子结点的调整过程为筛选。

   此过程的输出序列为从大到小。

其过程如图所示:






调整方法:

       输出堆顶元素之后,以堆中最后一个元素替代之;然后将根结

点值与左、右子树的根结点值进行比较,并与其中者进行交换;

重复上述操作,直至叶子结点,将得到新的堆,称这个从堆顶至

叶子的调整过程为筛选。

        此过程的输出序列为从小到大。




算法:

void HeapAdjust (S_TBL *h,int s,int m){             //a[s…m]中的记录关键码除a[s]外均满足堆的定义,本函数           将对第s个结点为根的子树筛选,使其成为大顶堆  ac=h->a[s];  for (j=2*s;j<=m;j=j*2)   //沿关键码较大的子女结点向下筛选   { if (j<m&&h->a[j].key<h->a[j+1].key)        j=j+1;                               //为关键码较大的元素下标     if (ac.key<h->a[j].key)  baeak;      // ac应插入在位置s上      h->a[s]=h->a[j]; s=j;                   // 使s结点满足堆定义   }  h->a[s]=ac;                             //  插入 }
void HeapSoat (S_TBL *h){ for (i=h->length/2;i>0;i- -)      // 将a[1..length]建成堆         HeapAdjust (h,i,h->length);  for (i=h->length;i>1;i- -)      {  h->a[1]<-->h->a[i];             // 堆顶与堆低元素交换           HeapAdjust (h,1,i-1);   // 将a[1..i-1]重新调整为堆       }}



算法评价:

时间复杂度:最好、坏情况下T(n)=O(nlogn)----n较大时比较有效

空间复杂度:S(n)=O(1)

堆排序为不稳定排序。








0 0
原创粉丝点击