您的位置:首页 > 其它

堆排序(heap sort)

2016-09-28 17:43 351 查看

堆排序

概述

对简单排序的一种改进

堆是具有下列性质的完全二叉树:

每个节点的值都大于或等于其左右孩子结点的值,称为大顶堆;

每个节点的值都小于或等于其左右孩子结点的值,称为小顶堆。

堆排序算法思想:

将待排序的列表,构造成一个大顶堆。最大值就是堆顶的根结点,将其移去(其实就是将第一个元素与最后一个元素对调,最后一个元素就是最大值),然后再对剩下的n-1个元素组成的序列从新排序成大顶堆。如此重复,就能得到一个有序序列。

循环方式实现代码

/*堆调整函数,注意我们对于顺序表sqlist默认是第一个元素不用
* 调整顺序表sqList在s与其左右子树的 序列,m是堆的长度
* */
public void heapAdjust(int sqList[],int s,int m){
int temp = sqList[s];
for (int i = 2*s ; i <= m; i*=2) {//沿着关键字大的向下筛选
if (sqList[i]<sqList[i+1] && i<m) {
i++;//j为记录关键字较大的下标
}
if (sqList[i] <= temp) {
break ;//已经满足堆排序条件,直接跳出
}
sqList[s] = sqList[i];
s = i ;
}
sqList[s] = temp;
}

/*对顺序表sqlsit进行多排序*/
public void heapSort(int sqList[]){
//首先对顺序表改成一个大堆顶
for (int i = sqList.length/2; i > 0; i--) {
heapAdjust(sqList, i,sqList.length);
}
for (int i = sqList.length; i > 1 ; i--) {
swap(sqList,1,i);//将最大的一个换到后边
heapAdjust(sqList, 1,i-1);//对除了已经排好序的记录进行堆调整
}
}


递归方式实现代码

/************************
* 大顶堆排序,堆为A[1...length],不用A[0]
**************************/

public int parent(int i) {
return i / 2;
}

public int leftChild(int i) {
return 2 * i;
}

public int rightChild(int i) {
return 2 * i + 1;
}

/*
* 用递归的思想实现堆调整
*
* @param sqList 是待调整的顺序表
*
* @param i 是需要调整元素的索引
*
* @param length 堆的长度
*/
public void heapAdjust(int[] sqList, int i, int length) {
int l = leftChild(i);
int r = rightChild(i);
int largest = i;// 最大值的索引
// 通过两次比较,从根和他的左右孩子之间找出最大值的索引
if (l <= length && sqList[i] < sqList[l]) {
largest = l;
}
if ( r <= length && sqList[largest] < sqList[r] ) {
largest = r;
}
// 将sqlist[largest]和sqlist[i]交换
if (largest != i) {
swap(sqList, i, largest);
// 由于sqlist[largest]和sqlist[i]交换,
// 可能造成sqlist不在满足大顶堆性质,所以要调整
heapAdjust(sqList, largest, length);
}
//如果largest==i则已经满足大顶堆条件,就不需要做任何操作。

}

// 建堆
// 由于我们不用sqlist[0],所以堆长度为length-1
public void buildHeap(int[] sqList) {
for (int i = (sqList.length-1) / 2; i > 0; i--) {
heapAdjust(sqList, i, (sqList.length-1));
}
}

// 堆排序
// 堆的长度为length-1
public void heapSort(int[] sqList) {
buildHeap(sqList);
for (int i = (sqList.length-1); i >= 2; i--) {
swap(sqList, 1, i);// 将根结点换到后边
heapAdjust(sqList, 1, i - 1);// 堆调整
}
}

public void swap(int array[], int i, int j) {
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}


堆排序时间复杂度

堆调整的时间复杂度为O(logi)

构建堆需要n-1次堆调整,所以构建堆时间复杂度为O(nlogn)

堆排序需要一次堆构,n-1次交换和n-1次堆调整。所以堆排序的时间复杂度为O(nlogn)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: