Unit 7 查找和排序

Q1:快速排序
Q2:冒泡排序
Q3:直接插入排序
Q4:折半插入排序
Q5:简单选择排序
归并排序
Q6:数组中最小的K个数
Q7:数据流中的中位数

Unit 7 Q1:快速排序

思想:
1.int Partition(int A[],int low,int high)
每一趟选择当前序列的第一个作为枢轴,将比枢轴小的放左边,比枢轴大的放右边,最后腾出位置放枢轴。
(比枢轴小的数…)枢轴(比枢轴大的数…),返回枢轴所谓位置
2.递归处理左右两边.

空间效率:平均O(logn)。最大递归深度:n。最小递归深度log2(n+1)向上取整
时间效率:最坏O(n^2)。基本有序、基本逆序
最好or平均:O(nlogn)。平均分为两个等长的表,速度更快

public void quicksort(int A[],int low,int high){
        if(low<high){
            int pivot=Partition(A,low,high);//定好,原来的A[0]现在的位置是pivot
            quicksort(A,low,pivot-1);
            quicksort(A,pivot+1,high);
        }
    }
int Partition(int A[],int low,int high){
        int temp=A[low];//temp存第一个
        //先左后右一直换
        while(low<high){
            //右碰小换
            while(low<high&&A[high]>=temp) high--;
            A[low]=A[high];
            //左碰大换
            while(low<high&&A[low]<=temp) low++;
            A[high]=A[low];
        }
        //都换完了。low位置左边都比temp小,右边都比temp大
        A[low]=temp;
        return low;//返回定好的第一个的值的位置
    }

 

Unit 7 Q2:快速排序

date:2019/12/3
思想:一趟冒泡将最小的元素交换到最前面,需(n-1)趟冒泡即可排好序
时间复杂度平均O(n ^ 2)。最好情况:初始有序,O(n)。最坏情况:初始逆序O(n^2)

public void bubblesort(int A[]){
	int n=A.length;
    for(int i=0;i<n-1;i++){
        boolean flag=false;//flag表示本趟是否发生交换
        for(int j=n-1;j>i;j--){
            if(A[j-1]>A[j]){//左边比右边大,换
                int temp=A[j-1];
                A[j-1]=A[j];
                A[j]=temp;
                flag=true;
            }
        }
        if(flag==false)//没发生交换,说明有序
            break;
    }
}

 

unit 7 Q3:直接插入排序

date:2019/12/3
适用于基本有序。
思想:每趟将未排序序列的第一个插入已排序序列中的相应位置,未排序序列为空时停止。
最好情况:序列有序.O(n)
最坏情况:序列逆序.O(n^2)

public void directInsertSort(int A[]){
    int n=A.length;
    //从第一个开始插
    for(int i=1;i<n;i++){
        int temp=A[i];
        //从已排序序列最后一个开始找,找到A[j]<temp<A[j+1]停止
        int j=i-1;
        for(;j>=0&&temp<A[j];j--)
            A[j+1]=A[j];
        A[j+1]=temp;//上次已经把A[j+1]位置的值移到A[j+2]位置上了 
    }
}

 

unit 7 Q4:折半插入排序

date:2019/12/4
思路:
直接插入排序基础上,使用折半查找法确定插入位置。仅适用于顺序表。
与直接插入排序的不同之处:减少了元素间比较的次数(移动次序不变,该移动的还得移动)

public void binaryInsertSort(int A[]){
    int i,n=A.length;
    for(i=1;i<n;i++){
        int temp=A[i];
        //折半查找。找到temp的插入位置A[mid+1]
        int low=0,high=i-1,mid=(low+high)/2;
        while(low<=high){
            mid=(low+high)/2;
            //终止条件:A[mid] <= temp < A[mid+1]
            if(A[mid]<=temp&&temp<A[mid+1])
                break;
            if(A[mid]<=temp)
                low=mid+1;
            if(temp<A[mid])
                high=mid-1;
        }
        //找到位置,temp插在A[mid+1]位置上
        //把mid+1到i-1,都向后挪一个
        for(int j=i-1;j>mid;j--)
            A[j+1]=A[j];
        //temp插在A[mid+1]位置上
        A[mid+1]=temp;
    }
}

 

unit 7 Q5:简单选择排序

date:2019/12/4
思想
每次从无序中选出一个最小的,将最小的与无序最头上替换,此时最头上有序。
经过(n-1)趟排序后有序。
特点
时间复杂度O(n^2)。元素很少移动;比较次数与初始序列无关=(1/2)n(n-1)

public void selectsort(int A[]){
    int n=A.length;
    for(int i=0;i<n-1;i++){
        //找无序中最小的,下标记为min_j
        int min_j=i;
        for(int j=i+1;j<n;j++){
            if(A[j]<A[min_j])
                min_j=j;
        }
        //交换
        int temp=A[i];
        A[i]=A[min_j];
        A[min_j]=temp;
    }
}

 

unit 7 Q6:数组中最小的K个数

剑指offer 40 牛客链接
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4。
date:2020/02/14
思路
利用快速排序中的获取分割(中轴)点位置函数Partitiion。
目的是找到index==k-1,使得比第k个数字小的所有数字都位于index的左边,比第k个数字大的所有数字都位于index的右边。调整之后,位于数组左边的k个数字就是最小的k个数字(这k个数字不一定是排序的)
时间复杂度O(N)
代码

    public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
        ArrayList<Integer> res=new ArrayList<Integer>();
        if(input==null||input.length<=0||k<=0||k>input.length)
            return res;
        int index,start=0,end=input.length-1;
        index=Partition(input,start,end);
        while(index!=k-1){
            //index比实际的位置靠左:小了,向右找
            if(index<k-1)
                start=index+1;
            else
                //index靠右了,向左找
                end=index-1;
            index=Partition(input,start,end);
        }
        for(int i=0;i<k;i++)
            res.add(input[i]);
        return res;
    }
    
    int Partition(int[] A,int low,int high){
        int temp=A[low];
        while(low<high){
            //右碰小换
            while(low<high&&A[high]>=temp) high--;
            A[low]=A[high];
            //左碰大换
            while(low<high&&A[low]<=temp) low++;
            A[high]=A[low];
        }
        A[low]=temp;
        return low;
    }

 

unit 7 Q7:数据流中的中位数

剑指offer 41 牛客链接
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。
date:2020/02/15
思路:
设置一个大顶堆,一个小顶堆,堆用java中优先队列实现。

    //小顶堆、大顶堆的java实现
    private PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>()private PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(15, new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2 - o1;
        }

大顶堆中最大者(根)小于 小顶堆中最小者(根)

  • 插入规则
    奇数:插入小顶堆;将小顶堆中最小者(根)插入大顶堆
    偶数:插入大顶堆;将大顶堆中最大者(根)插入小顶堆
  • 取出规则
    奇数:小顶堆中取其根节点
    偶数:小顶堆、大顶堆根节点的平均值

全部代码:

    //小顶堆
    private PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();
     
    //大顶堆。要重写
    private PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(15, new Comparator<Integer>() {
        @Override
        public int compare(Integer o1, Integer o2) {
            return o2 - o1;
        }
    });
     
    //记录偶数个还是奇数个
    int count = 0;
    //每次插入小顶堆的是当前大顶堆中最大的数
    //每次插入大顶堆的是当前小顶堆中最小的数
    //这样保证小顶堆中的数永远大于等于大顶堆中的数
    //中位数就可以方便地从两者的根结点中获取了
    public void Insert(Integer num) {
        //奇数
        if(count%2==1){
            minHeap.offer(num);//插入小顶堆
            int min=minHeap.poll();
            maxHeap.offer(min);//将小顶堆中最小者(根)插入大顶堆
        }else{
            //偶数
            //插入大顶堆
            maxHeap.offer(num);//插入大顶堆
            int max=maxHeap.poll();
            minHeap.offer(max);//将大顶堆的最大者(根)插入小顶堆
        }
        count++;
    }
    public Double GetMedian() {
        double res;
        //奇数,从小顶堆中取根结点
        if(count%2==1)
            res=minHeap.peek();
        else
            //偶数。大顶堆和小顶堆根节点的平均值
            res=(minHeap.peek()+maxHeap.peek())/2.0;
        return res;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值