归并,快速,堆排序~

堆排序

堆排序利用了大根堆(或小根堆)堆顶记录的关键字最大(或最小)这一特征,使得在当前无序区中选取最大(或最小)关键字的记录变得简单。

  (1)用大根堆排序的基本思想

  ① 先将初始文件R[1..n]建成一个大根堆,此堆为初始的无序区

  ② 再将关键字最大的记录R[1](即堆顶)和无序区的最后一个记录R[n]交换,由此得到新的无序区R[1..n-1]和有序区R[n],且满足R[1..n-1].keys≤R[n].key

  ③由于交换后新的根R[1]可能违反堆性质,故应将当前无序区R[1..n-1]调整为堆。然后再次将R[1..n-1]中关键字最大的记录R[1]和该区间的最后一个记录R[n-1]交换,由此得到新的无序区R[1..n-2]和有序区R[n-1..n],且仍满足关系R[1..n-2].keys≤R[n-1..n].keys,同样要将R[1..n-2]调整为堆。

  ……

  直到无序区只有一个元素为止。

  (2)大根堆排序算法的基本操作:

  ① 初始化操作:将R[1..n]构造为初始堆;

  ② 每一趟排序的基本操作:将当前无序区的堆顶记录R[1]和该区间的最后一个记录交换,然后将新的无序区调整为堆(亦称重建堆)。

  注意:

  ①只需做n-1趟排序,选出较大的n-1个关键字即可以使得文件递增有序。

  ②用小根堆排序与利用大根堆类似,只不过其排序结果是递减有序的。堆排序和直接选择排序相反:在任何时刻堆排序中无序区总是在有序区之前,且有序区是在原向量的尾部由后往前逐步扩大至整个向量为止

特点

   堆排序(HeapSort)是一树形选择排序。堆排序的特点是:在排序过程中,将R[l..n]看成是一棵完全二叉树的顺序存储结构,利用完全二叉树中双亲结点和孩子结点之间的内在关系(参见二叉树的顺序存储结构),在当前无序区中选择关键字最大(或最小)的记录

堆排序的最坏时间复杂度为O(nlogn)。堆序的平均性能较接近于最坏性能。

不稳定的排序算法

代码

View Code
 1 void adjust(int i,int n)//调整为小顶堆
 2 {
 3     int j = i,k;
 4     a[0] = a[i];
 5     j = 2*i;
 6     while(j<=n)
 7     {
 8         if(j < n&&a[j]>a[j+1])//左右孩子结点的最小值
 9             j++;
10         if(a[0]>a[j])//如果比最小值大
11         {
12             a[i] = a[j];//当前最小值孩子结点上移 i变为当前j值 继续与下面比较
13             i = j;
14             j = 2*j;
15         }
16         else
17             break;
18     }
19     a[i] = a[0];//放在合适位置
20 }
21 void heapsort(int n)
22 {
23     int i,t;
24     for(i = n/2 ; i>0 ; i--)//最初调整为堆
25         adjust(i,n);
26     for(i = n ; i>1 ; i--)//依次交换根节点和尾结点
27     {
28         t = a[1];
29         a[1] = a[i];
30         a[i] = t;
31         adjust(1,i-1);
32     }
33 }

 快速排序

设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用第一个数据)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。

最坏 时间复杂度为o(n2)。

最佳 T(n)=θ(nlogn)

代码

View Code
 1 /*
 2  一趟快速排序的算法是:   
 3  找一个记录,以它的关键字作为“枢轴”,
 4  凡其关键字小于枢轴的记录均移动至该记录之前,
 5  反之,凡关键字大于枢轴的记录均移动至该记录之后。
 6  A[0] A[1] A[2] A[3] A[4] A[5] A[6]:   
 7  49   38    65   97   76   13   27   

 8  进行第一次交换后:
 9  27 38 65 97 76 13 49   
10  进行第二次交换后:
11  27 38 49 97 76 13 65   
12  进行第三次交换后:27 38 13 97 76 49 65    
13  进行第四次交换后:27 38 13 49 76 97 65 
14  */
15  int fqsort(int low,int high,int a[])
16  {
17      int i = low,j = high,k = a[low];//找一个比较的点
18      while(i<j)
19      {        
20          while(i<j&&a[j]<=k)//从右向左移直至找到比k大的数
21              j--;
22          a[i] = a[j];//比这个数大的放左边
23          while(i<j&&a[i]>=k)//从左向右移直至找到比k小的数
24              i++;
25          a[j] = a[i];//比这个数大的放右边
26      }
27      a[i] = k;
28      return j;//j左右两边已经被k分割开 再把j+1当作右边一组的low j-1当作左边一组的high进行下一次的快排
29  }
30  void qsort(int low,int high,int a[])
31  {
32      int q;
33      if(low<high)
34      {        
35          q = fqsort(low,high,a);//找到分割点
36          qsort(low,q-1,a);//左右两边进行快排
37          qsort(q+1,high,a);
38      }
39  }

 归并排序

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法(Divide and Conquer)的一个非常典型的应用。

将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为2-路归并。

归并排序是稳定的排序.即相等的元素的顺序不会改变.如输入记录 1(1) 3(2) 2(3) 2(4) 5(5) (括号中是记录的关键字)时输出的 1(1)
2(3) 2(4) 3(2) 5(5) 中的2 和 2
是按输入的顺序.这对要排序数据包含多个信息而要按其中的某一个信息排序,要求其它信息尽量按输入的顺序排列时很重要.这也是它比快速排序优势的地方.

 代码

View Code
posted @ 2012-07-21 14:29  某某。  阅读(248)  评论(0编辑  收藏  举报