面试题:利用堆排序实现从n个数字中找出前top-k大的数字

#用堆排序(最小堆):top-k最大的数字

题目:top-k算法,从n个大小的数组中,找出k个最大的数字并输出

输入:数组大小n=10;k的值为5;数组为:9,8,3,2,10,20,13,1,5

输出:20,13,10,9,8

思路:1、维护k个最小堆,如果某个新进来的数字大于最小堆的根节点,那么将根节点换为新进来的数字,然后在对最小堆进行调整。
2、在找出k个大的数字后,对k个大的数字进行一次堆排序,因为我们做的是最小堆,所以堆排序后得到的序列就是升序的序列
Ps:堆排序的平均时间复杂度都为O(n*logn),它比快排好的地方是,快排在最坏的情况下(数组已有序)时间复杂度为O(n^2)

/*
题目:堆排序的用法:
	  1、利用堆排序从n个数字中取出top-k个最大的数字
	  2、主要使用最小堆,维护k个大小的最小堆
*/
#include
#include
using namespace std;

void headAdjust(vector &arr, int start, int end){
	//i这里指向的是左子树
	int i = start * 2 + 1;
	while (i <= end){
		//先找左右子树中最小的
		if (i + 1 <= end&&arr[i] > arr[i + 1]){
			//如果左子树大于右子树,则i指向右子树
			i++;
		}
		if (arr[start] > arr[i]){
			swap(arr[start], arr[i]);
			start = i;
			i = 2 * start + 1;
		}
		else{
			break;
		}
	}
}

void heapSort(vector &arr, int start, int end){
	//堆排序是从第一个非叶节点开始从下往上更新,直到更新到根节点为止
	for (int i = (end - 1) / 2; i >= 0; i--){
		headAdjust(arr,i,end);
	}
	//下面进行堆排序,进行堆排序的时候,因为上面已经调整过一遍堆了,这次只是替换了堆顶元素,所以只需要对堆顶元素进行一次调整即可。
	for (int i = end; i-1 >= 0; i--){
		swap(arr[i], arr[0]);
		headAdjust(arr, 0, i-1);
	}
}

int main(){
	//堆排序维护k个大小的最小堆
	int k;
	int n;
	cin >> n;
	cout << "top-k的值为:";
	cin >> k;
	cout << "依次输入数组,然后找出top-" << k << "个值" << endl;
	vector arr(k,0);
	for (int i = 0; i < n; i++){
		if (i > k - 1){
			int temp;
			cin >> temp;
			if (temp > arr[0]){
				arr[0] = temp;
				headAdjust(arr, 0, k - 1);
			}
		}
		else{
			int temp;
			cin >> temp;
			arr[i] = temp;
			if (i == k - 1){
				//这里先建堆
				for (int j = (k - 1 - 1) / 2; j >= 0; j--) {
					heapAdjust(arr, j, k-1);
				}
			}
		}
	}
	//对堆进行最小堆排序
	heapSort(arr, 0, k - 1);
	for (int i = 0; i < arr.size(); i++){
		cout << arr[i];
		if (i < arr.size()-1){
			cout << " ";
		}
	}
	system("pause");
	return 0;
}

你可能感兴趣的:(面试题,数据挖掘)