9.3 堆排序(排序(上))
堆排序
文章目录
- 堆排序
- 9.1 选择排序(不稳定)
- 9.2 堆排序(不稳定)
- 9.3 内容补充
9.1 选择排序(不稳定)
**核心思想:**每一趟从待排序序列中选择最小(或最大)的元素,放到已排好序列的末尾
-
第一趟:找到最小的元素,放到数组开头
-
第二趟:在剩下的元素中寻找最小的元素,放到数组第二个位置
-
重复此过程至最后一个元素
代码实现:
/*
**作用:查找未排序部分的最小元下标
*/
int scan_for_min(element_type A[],int i, int N)
{int j;int min_position = i;for (j = i; j < N; j++){if (A[j] < A[min_position]) //如果发现更小的元素min_position = j; //更新下标}return min_position;
}/*
**作用:交换数组中两元素位置
*/
void swap(element_type A[], int i, int j)
{element_type temp = A[i]; //临时变量A[i] = A[j];A[j] = temp;
}/*
**作用:选择排序算法
*/
void selection_sort(element_type A[], int N)
{int min_position;int i;for (i = 0; i < N - 1; i++){ //最后一趟没必要再寻找最小值,因此是N - 1//从A[i]到A[N - 1]中找最小元,将其位置赋值给min_positionmin_position = scan_for_min(A, i, N);//将未排序部分的最小元换到有序部分的最后位置swap(A, i, min_position);}
}
时间复杂度:无论如何T = θ( N2^2 ),因此我们使用最小堆来帮助我们优化选择排序
9.2 堆排序(不稳定)
**核心思想:**利用堆这种数据结构来快速选出当前最大(最小)的元素,并将其放至最终位置(通常使用大根堆)
具体步骤:
- 将无序数组调整为大根堆
- 取出堆元素
- 栈顶元素为当前最大值,将其与堆的最后一个元素交换
- 堆的大小减1
- 对新的栈顶执行下滤操作
- 重复步骤2,直至堆大小为1
代码实现:
堆排序处理N个随机排列的不同元素,平均比较次数为2NlogN - O( NloglogN )
/*
**作用:交换数组中两元素位置
*/
void swap(element_type A[], int i, int j)
{element_type temp = A[i]; //临时变量A[i] = A[j];A[j] = temp;
}/*
**作用:将N个元素的数组中以A[p]为根的子堆调整为最大堆
*/
void perc_down(element_type A[], int p, int N)
{element_type x;int parent, child;x = A[p];//如果还有孩子结点for (parent = p; 2 * parent + 1 < N; parent = child){child = 2 * parent + 1;//child指向较大的孩子结点(若右孩子结点存在)if (child + 1 < N && A[child] < A[child+1])child++;if (x >= A[child]) break; //找到了合适位置else A[parent] = A[child]; //下滤}A[parent] = x;
}/*
**作用:堆排序
*/
void heap_sort(element_type A[], int N)
{int i;//建立最大堆for (i = (N - 1) / 2; i >= 0; i--) //从第一个非叶结点开始调整perc_down(A, i, N);for (i = N - 1; i > 0; i--){ //当i=0时无需调整swap(A, i, 0);perc_down(A, 0, i);}
}
注:虽然堆排序给出最佳平均时间复杂度,但实际效果一般不如用Sedgewick增量序列的希尔排序
9.3 内容补充
1. 博客园:十大经典排序算法(动图演示)
2. 博客园:Java冒泡排序、选择排序、插入排序、希尔排序、归并排序、快速排序
3. 博客园:堆排序算法
4. CSDN:四大排序——冒泡排序、选择排序、插入排序、堆排序