n个数里找最大的m个Topk-堆排序快排,非递归

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);
        }
    }
}
 

你可能感兴趣的:(算法)