堆排序算法详解

最大堆:每一个结点都比其子结点大的二叉树。

堆排序思想:把所有数据建成一个最大堆,不停的把堆顶的元素取出来依次排列,取一个数之后,剩下的数要维持最大堆结构

 那么堆排序主要分为

  1. 建成最大堆
  2. 维持堆结构

建最大堆 :时间复杂度为O(n)

注意:在使用数组表示的堆结构中,结点arr[index]的父结点为arr[(index - 1) / 2].

建堆思想: 把数组中的每一个数遍历一次,如果它比父结点要大就与父结点交换,知道它小于等于父结点

//arr:所有数据所在数组  index:当前处理的数下标
//因为(0 - 1) / 2 = 0所以不会越界
void buildHeap(int arr[], int index) {
	while (arr[index] > arr[(index - 1) / 2]) {
		swap(arr[index], arr[(index - 1) / 2]);
		index = (index - 1) / 2;
	}
}

维持堆的结构:时间复杂度log(n),每一次维持堆为log(n)

注意:一个结点arr[index]的左孩子为arr[index * 2 + 1],右孩子为arr[index * 2 + 2]

维持堆结构思想:从arr[0]开始,选取它和它的左右孩子中最大的那个,如果最大的是自己,不是左右孩子,结束;如果最大的是左右孩子中的一个,将其与父结点交换位置;重复上述过程。

代码如下:

//curIndex:当前处理的数的下标  heapSize:目前堆的大小
//leftChild: 当前数的左孩子
//largestIndex:当前数与其左右孩子中最大的数的下标
void heapify(int arr[], int curIndex, int heapSize) {
	int leftChild = curIndex * 2 + 1;
	int largestIndex;
	while (leftChild < heapSize) {
		largestIndex = leftChild + 1 < heapSize && arr[leftChild] < arr[leftChild + 1] 
					? leftChild + 1 : leftChild;
		largestIndex = arr[largestIndex] > arr[curIndex] ? largestIndex : curIndex;
		if (curIndex == largestIndex){
			break;
		}
		swap(arr[largestIndex], arr[curIndex]);
		curIndex = largestIndex;
		leftChild = curIndex * 2 + 1;
	}
}

堆排序主函数如下

void heapSort(int arr[], int heapSize) {
	if (heapSize < 2) return;
	//建立最大堆
	for (int i = 0; i < heapSize; i++) {
		buildHeap(arr,i);
	}

	swap(arr[0], arr[--heapSize]);
	while (heapSize){
		heapify(arr, 0, heapSize);
		swap(arr[0], arr[--heapSize]);
	}
}

猜你喜欢

转载自blog.csdn.net/qianji_little_boy/article/details/83514288