算法(第四版)之堆排序

堆排序是建立在堆的基础上的, 了解堆排序我们得先了解二叉堆. 二叉堆是以二叉树为基础的, 当一棵二叉树的每个结点都大于等于它的两个子节点数时, 它被称为堆有序. 我们可以很容易的理解出, 它的根节点是最大节点

二叉堆可以用指针和数组两种方式表示, 本文用的是数组的方式.

我们在堆中有两种操作方法, 一种叫做上浮, 一种叫做下潜, 上浮是指将节点n和它的父节点进项比较, 如果它的父节点小于它, 则节点n与它的父节点交换, 然后在继续与它交换后的父节点进行比较, 知道它的父节点不小于它为止. 而下潜则相反, 节点n 将于它的两个子节点比较, 当它的子节点大于它时, 它将于较大的那个子节点进行交换, 以此类推, 因为本文重点讲的是堆排序, 只用到了下潜, 所以只给出下潜代码:

 1     public static void sink(int[] a, int i, int N){ // 将小的数字下沉
 2             while(i*2+1 < N) {
 3                 int j = i*2+1;
 4                 if(j < N-1 && a[j] < a[j+1]) {
 5                     j++;
 6                 }
 7                 if(a[i] > a[j])
 8                     break;
 9                 exch(a, i, j);
10                 i = j;
11             }
12     }

然后我们讲一下堆排序. 堆排序分为两个步骤, 一个是将代码进行堆有序化, 从第n/2个结点到第一个结点分别进行下潜操作, 接着进行下沉排序, 将根节点与最后一个结点进行交换, 在将排除了最后一个数的数组对根节点作下潜操作, 然后将根节点和第n-1个结点交换, 以此类对, 知道到了最后一个结点

附上代码:

1     public static void hashSort(int[] a, int N) {
2             for(int i = N/2; i >= 0; i--) { // 实现堆有序
3                     sink(a, i, N);
4             }
5             for(int i = N-1; i >= 0; i--) { // 排序
6                 exch(a, 0, i);
7                 sink(a, 0, i);
8             }
9     }

我的代码和书上的有些不同, 因为我的代码是从0开始的, 而书上的是从1开始的, 这只是我的个人习惯, 按照书上说的, 从一开始更加符合大多数程序员的习惯, 也更加方便

堆排序的时间复杂度为O(nlogn)

猜你喜欢

转载自www.cnblogs.com/qq1914808114/p/10878727.html