面试:数组:Topk _1

题目

求一维数组中最小的k个数字

快排算法

复杂度:O(klgn)

import java.util.*;

class Solution{
     //选择一个数,将数组分为大小两个部分
    public int partition(int data[],int start,int end){
        int pivotvalue=data[start];

        while(start<end){
            while(start<end && data[end]>=pivotvalue)
                --end;

            // 将比pviot小的元素移动到低端,此时right空,等待低位比pviotvalue大的数补上
            data[start]=data[end];

            while(start<end && data[start]<=pivotvalue)
                ++start;

            //此时比pviot大的元素移动到了高端,此时left位相当于空,等待高位比pivotalue小的数补上
            data[start]=data[end];
        }

        //当start=end,完成一次快速排序,此时left相当于空,等待pivotvalue补上
        data[start] = pivotvalue;

        return start;

    }

    // 若返回的小标是k-1,则结束;否则,调用partition到下标为k-1

    public void getTopk(int[] data,int k){
        int start = 0,end = data.length-1;
        int index=partition(data,start,end);
        while(index!=k-1){
            if(index>k-1){
                // 从index前面重新查找
                 end = index-1;
                 index = partition(data,start,end);
            }else{
                start=end-1;
                index=partition(data,start,end);
            }
        }

        for(int i=0;i<k;i++)
            System.out.println(data[i]+"\t");

    }

}

堆排序算法

复杂度:O (nlgK)

算法;
1. 创建小根堆,初始化大小为k,堆顶为堆得最大元素
2. 扫描数组,往最小堆插入数据,如果堆得元素个数达到k,那么新元素需要和堆顶元素比较,如果小于堆顶,插入新元素。
3. 最终得到k个最小元素。

import java.util.*;

class MinHeap{
    // 堆存储数组
    private int[] data;

    // 构建小根堆
    public  MinHeap(int[] data){
        this.data=data;
        bulidHeap();
    }

    // 数组转换为小根堆
    private void bulidHeap(){
        for(int i=(data.length)/2-1;i>=0;i--)
            heapify(i); // 对孩子节点调用heapify
    } 

    //简化写法
    private void heapify(int k){
        int N=data.length;
        while(2*k<=N){
            int j=2*k;
            if(j<N && less(j,j+1))
                j++;
            if(!less(k,j))
                break;
            exch(k,j);
            k=j;
        }
    }

    /* // 好理解的写法 private void heapify(int k){ // 获取左右节点的数组的下标 int l=left(i); int r =right(i); // 临时变量 int smallest=i; //若存在左节点,且左节点的值下于根节点 if(l<data.length && data[l]<data[i]) smalleat=l; if(r<data.length && data[r]<data[smalleat]) smalleat=r; // 左右节点都大于根节点直接return if(i==smallest) return; //交换节点 swap(i,smalleat); // 交替后左右子树有影响,对收影响的子树再次heapify heapify(smalleat); } */


    private boolean less(int i,int j)
    {
        if(data[i]<data[j])
            return true;
        else
            return false;
    }

    private void exch(int i, int j)
    {
        int key=data[i];
        data[i]=data[j];
        data[j]=key;

    }

    public int getRoot(){
        return data[0];
    }

    // 替换根节点,并重新heapify

    public void setRoot(int root)
    {
        data[0]=root;
        heapify(0);
    }
}

public class Solution{
    public static void main(String[] args){
        // 元数据
        int[] data={56,275,12,6,45,478,41,1236,456,12,546,45};

        //top5
         int[] top5=topk(data,5);
         for(int i=0;i<5;i++)
             System.out.println(top5[i]);
    } 

    private static int[] topk(int[] data,int k){
        //取得k个元素放入一个数组topk中
        int[] topk=new int [k];
        for(int i=0;i<k;i++)
            topk[i]=data[i];

        // 转换为小根堆
        MinHeap heap =new MinHeap(topk);

        for(int i=k;i<data.length;i++){
            int root = heap.getRoot();

            //根据大于堆中最小的数 ,替换堆中的根节点,再转换为堆

            if(data[i]>root)
                heap.setRoot(data[i]);
        }
        return topk;

        }
    }

你可能感兴趣的:(面试:数组:Topk _1)