- 简单选择排序
- 堆排序
简单选择排序
原理非常简单
n 个元素的数组,i = 1,2,3,…
从 n-i+1 个元素中选出最大(小)的元素
与第 i个元素交换
当然简单的方法效率不是很理想,很容易看出简单选择排序的时间复杂度为 O(n2) 。
我的代码如下
public static void sort(int[] data){
int len = data.length;
for(int i = 0; i < len; i ++){
int min = i;
for(int j = i; j < len; j ++){
if(data[j] < data[min] ){
min = j;
}
}
if(i != min){
int temp = data[i];
data[i] = data[min];
data[min] = temp;
}
}
}
堆排序
堆
首先介绍一下 堆 的概念,
n个元素的序列 , , 当且仅当满足以下关系时,称之为堆
{ki≤k2iki≤k2i+1(小顶堆)
或{ki≥k2iki≥k2i+1(大顶堆)
其中
(i=1,2,⋯,⌊n2⌋)
这个定义放在一个一维数组上是不好理解的,如果我们把这样的序列看成一颗 完全二叉树 就好理解的多了。
完全二叉树中的所有非叶子结点的值均不大于(不小于)其左、右孩子结点的值。
如图:
由图可知堆顶元素( 树的根结点)是序列的最大(最小)值。
堆排序就是利用了堆的这一特点。
原理如下
n 个元素的数组,i = 1,2,3,…
将数组构造成堆
输出堆顶元素
调整剩余 n - i 个元素构建成堆
问题在于
(1)怎样将无序数组建成堆
(2)怎样调整剩余元素成新堆
调整剩余元素成新堆
大家应该都会觉得第二个问题简单一些,因为剩余元素即左右子树,已经是堆。
堆排序中,当输出堆顶元素后,以最后一个元素代替成为堆顶。仅需自顶而下的比较、调整就能生成新的堆。
如图
将无序数组建成堆
如果上一步调整的操作叫做 “筛选”,那么将无序数组建成堆的过程就是重复 “筛选”的过程,我们从第一个非叶子结点(在完全二叉树中 是第
⌊n2⌋
个元素)开始向对所有非叶子结点执行“筛选”。
如图
堆排序的时间复杂度
容易看出每次“筛选”的时间复杂度是 O(lgn) 。而完成排序至少执行 n−1 次“筛选”。所义堆排序的时间复杂度为 O(nlgn) 。
我的代码下
/**
* 堆排序
* @param data 待排序数组
*/
public static void sort(int[] data){
buildMaxHeap(data);
int temp = 0;
int size = data.length;
for(int i = data.length - 1; i > 1; i --){
temp = data[i];
data[i] = data[1];
data[1] = temp;
size --;
maxHeapify(data,1,size);
}
}
/**
* 初次构建堆
* @param data 待排序数组
*/
public static void buildMaxHeap(int[] data){
int len = (data.length-1) / 2;
int size = data.length;
for(int i = len; i > 0; i --){
maxHeapify(data,i,size);
}
}
/**
* "筛选" 操作
* @param data 待排序数组
* @param i 堆顶元素的索引
* @param size 堆的大小
*/
public static void maxHeapify(int[] data, int i,int size){
int l = left(i);
int r = right(i);
int largest = 0;
if(l< size && data[l] > data[i]){
largest = l;
}else{
largest = i;
}
if( r < size && data[r] > data[largest]){
largest = r;
}
if(largest != i){
int temp = data[i];
data[i] = data[largest];
data[largest] = temp;
maxHeapify(data,largest,size);
}
}
/**
* 得到左孩子
* @param i 父结点索引
* @return 左孩子结点索引
*/
public static int left(int i){
return i*2;
}
/**
* 得到右孩子
* @param i 父结点索引
* @return 右孩子结点索引
*/
public static int right(int i){
return i * 2 + 1;
}
[1] 严蔚敏 . 数据结构(c语言版)
[2] 算法导论