1.最简单的方法:将n个数排序,排序后的前k个数就是最大的k个数,这种算法的复杂度是O(nlogn)
2.O(n)的方法:利用快排的patition思想,基于数组的第k个数来调整,将比第k个数小的都位于数组的左边,比第k个数大的都调整到数组的右边,这样调整后,位于数组右边的k个数最大的k个数(这k个数不一定是排好序的)
3.O(nlogk)的方法:先创建一个大小为k的最小堆,接下来我们每次从输入的n个整数中读入一个数,如果这个数比最小堆的堆顶元素还要大,那么替换这个最小堆的堆顶并调整。
package io.fredia;
/**
* 堆排序
*
*/
public class HeapSortTest {
public static void main(String[] args) {
HeapSortTest heapSort = new HeapSortTest();
int[] ran = new int[100];
int[] out = heapSort.getRandomIndexArray(ran, ran.length, 5);
print(ran);
print(out);
}
public int[] getRandomIndexArray(int[] random, int mapSize,
int numberOfIndex) {
int[] indexes = getInitialArray(numberOfIndex);
for (int i = 0; i < mapSize; i++) {
int randomNum = (int) (Math.random() * 1000);
random[i] = randomNum;
if (i > numberOfIndex) {
insertNumIntoHeap(indexes, randomNum);
} else if (i == numberOfIndex) {
heapSort(indexes);
} else {
indexes[i] = randomNum;
}
}
return indexes;
}
public int[] getInitialArray(int numOfIndex) {
int[] indexes = new int[numOfIndex];
for (int i = 0; i < numOfIndex; i++) {
indexes[i] = -1;
}
return indexes;
}
public int[] insertNumIntoHeap(int[] numbers, int numToInsert) {
if (numToInsert > numbers[0]) {
numbers[0] = numToInsert;
compareAndExchange(numbers, 0);
}
return numbers;
}
private void compareAndExchange(int[] numbers, int index) {
int leftChildIndex = (index + 1) * 2 - 1;
int rightChildIndex = leftChildIndex + 1;
if (rightChildIndex > numbers.length) {
return;
} else if (rightChildIndex == numbers.length) {
if (numbers[index] > numbers[leftChildIndex]) {
swap(numbers, index, leftChildIndex);
}
} else {
int changeIndex = index;
if (numbers[index] > numbers[leftChildIndex]) {
changeIndex = leftChildIndex;
}
if (numbers[rightChildIndex] < numbers[changeIndex]) {
changeIndex = rightChildIndex;
}
if (changeIndex != index) {
swap(numbers, index, changeIndex);
compareAndExchange(numbers, changeIndex);
}
}
}
public static void swap(int[] data, int i, int j) {
if (i == j) {
return;
}
data[i] = data[i] + data[j];
data[j] = data[i] - data[j];
data[i] = data[i] - data[j];
}
public static void heapSort(int[] data) {
for (int i = 0; i < data.length; i++) {
createMaxdHeap(data, data.length - 1 - i);
swap(data, 0, data.length - 1 - i);
print(data);
}
}
public static void createMaxdHeap(int[] data, int lastIndex) {
for (int i = (lastIndex - 1) / 2; i >= 0; i--) {
// 保存当前正在判断的节点
int k = i;
// 若当前节点的子节点存在
while (2 * k + 1 <= lastIndex) {
// biggerIndex总是记录较大节点的值,先赋值为当前判断节点的左子节点
int biggerIndex = 2 * k + 1;
if (biggerIndex < lastIndex) {
// 若右子节点存在,否则此时biggerIndex应该等于 lastIndex
if (data[biggerIndex] < data[biggerIndex + 1]) {
// 若右子节点值比左子节点值大,则biggerIndex记录的是右子节点的值
biggerIndex++;
}
}
if (data[k] < data[biggerIndex]) {
// 若当前节点值比子节点最大值小,则交换2者得值,交换后将biggerIndex值赋值给k
swap(data, k, biggerIndex);
k = biggerIndex;
} else {
break;
}
}
}
}
public static void print(int[] data) {
for (int i = 0; i < data.length; i++) {
System.out.print(data[i] + "\t");
}
System.out.println();
}
}
快排(非递归)
int partition(int* arr, int low, int high)
{
int pivot = arr[low];
while(low < high)
{
while(low < high && arr[high] >= pivot)
high--;
arr[low] = arr[high];
while(low < high && arr[low] <= pivot)
low--;
arr[high] = arr[low];
}
arr[low] = pivot;
return low;
}
void non_recursive_qsort(int* arr, int low, int high)
{
stack<int> s;
int pivot;
if(low < high)
return ;
pivot = partition(arr, low, high)
if(low < pivot - 1)
{
s.push(low);
s.push(pivot - 1);
}
if(high > pivot + 1)
{
s.push(high);
s.push(pivot + 1);
}
//其实就是用栈保存每一个待排序子串的首尾元素下标,下一次while循环时取出这个范围,对这段子序列进行partition操作
//如果pivot的左段或右段已经少于两个元素了,则无需再对这个子段partition了
while(!s.empty())
{
high = s.top();
s.pop();
low = s.top();
s.pop();
pivot = partition(arr, low, high)
if(low < pivot - 1)
{
s.push(low);
s.push(pivot - 1);
}
if(high > pivot + 1)
{
s.push(high);
s.push(pivot + 1);
}
}
}