复试03-查找和排序

很多时候,不需要自己写一个排序查找算法,只需要借用写好的。
虽然有写好的,但是我那边学校招生简章上要求是java或c。没有c++所以说有可能需要自己写算,不能直接调用,因为c的函数库不太了解。
如果有ide的话就直接看源码好了。看完再调用测试。

Arrays工具类有2个常用的方法

import java.util.Arrays;

Arrays.sort(int[] a, int fromIndex, int toIndex);//仅排序fromIndex到toIndex下标的数据
Arrays.sort(int[] a);
//都是默认增序排列
int i1 = Arrays.binarySearch(a, 3);
//二分查找,在a中查3的位置,0开始(一定是在排好序中的数组中查找)

例题3.1

在这里插入图片描述
如果是逆序排序则把int[]类型转换为Interger[]型,然后在原来的排序基础上,额外添加一个参数。Collections.reverseOrder()

import java.util.Collections;
Arrays.sort(a,Collections.reverseOrder());//逆序

第二点就是自定义数据类型了。

自定义数据类型

两种方法:

  1. 设计比较函数
  2. 定义大小关系
例题3.2

在这里插入图片描述
https://www.cnblogs.com/blogxjc/p/9687297.html
java随机数

Random random = new Random(1);
random.

这种情况,明显要定义一个类。实现comparable接口,再实现compareTo方法

Comparable接口
class  Student implements Comparable<Student> {
    int number;//学号
    int score;//成绩
    Student(int number,int score){
        this.number = number;
        this.score = score;
    }
    @Override
    public int compareTo(Student o) {
        return this.score - o.score;//负数,0,正数  对应 小于,等于,大于
        //也就是说,this在前面是升序,
        //反之就是降序
    }
}

否则就是用冒泡排序。

冒泡
        Student studentx = new Student(-1, -1);

        for (int i = 0; i < n; i++) {
            for (int i1 = i; i1 < n; i1++) {//冒泡排序
                 if(!Compare(student[i], student[i1]) ){
                     studentx=student[i];
                     student[i]=student[i1];
                     student[i1]=studentx;
                 }
            }
        }
        for (Student student1 : student) {
            System.out.print(student1.number);
            System.out.print("---");
            System.out.println(student1.score);
        }


    static boolean Compare(Student x,Student y){
        if(x.score == y.score){//如果成绩一样,就按学号顺序排名
            return x.number<y.number;
        }else {
            return x.score< y.score;//如果x成绩小就是true
        }
    }


class  Student {
    int number;//学号
    int score;//成绩
    Student(int number,int score){
        this.number = number;
        this.score = score;
    }
}

最后一种方式就是重载符号

重载符号

很遗憾,java不支持重载符号。
下面是c++和c才有的特性。
在这里插入图片描述

例题3.2

在这里插入图片描述
这里突然卡壳了,后来想了想才反应过来,这里的话,光是数组是很麻烦得,必须得上表。因为奇偶数的个数不能确定。

import java.util.*;

public class c3 {
    public static void main(String[] args) {
        Random random = new Random(1);
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();
        ArrayList arrayList = new ArrayList();
        ArrayList arrayList1 = new ArrayList();//存偶数
        ArrayList arrayList2 = new ArrayList();//存奇数
        for (int i = 0; i < n; i++) {
            arrayList.add(random.nextInt(100));
        }
        for (Object o : arrayList) {
            if((int)o%2==0)arrayList1.add(o);
            else arrayList2.add(o);
        }
        Collections.sort(arrayList1);
        Collections.sort(arrayList2);

        System.out.println(arrayList1);
        System.out.println(arrayList2);
    }
}

再稍微修改一下输出格式就好啦。我这里偷个懒。
排序算法的特性,
线性排序–>奇数排序
逆序数对–>归并排序

排序算法的时间下界是nlogn,(基于比较)
如果要突破下限,也就是说要达到n的时间复杂度必须要给定范围
在这里插入图片描述
该组数据是需要辅助数组,分别是0出现了多少次,1出现了多少次,2出现了多少次。等等。
在这里插入图片描述
可以看出,我们仅需要再次遍历辅助数组,就可以得到顺序或逆序序列。总的时间来说应该是2N,可以姑且认为比nlogn时间小。

例题 sort

在这里插入图片描述
这里用java就稍微有点头疼,所以我稍微思考了一下。详细都写在下面啦。

import java.util.Scanner;

public class c4 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        int n = scanner.nextInt();//n个数
        int m = scanner.nextInt();//m数值
        scanner.nextLine();
//        这里尤为注意的是nextInt()后的\n会被识别为nextline();所以说要额外多一个nextline来吸收掉
//        比如说
//        5 3
//        3 -35 92 213 -644
//        第一行的3后面有一个换行符\n,这个换行符必须被占据掉才能正确读取第二行的数据,nextInt()不吸收换行符\n。
        int[] arr = new int[1000010];//数组,为了避免下标问题,就变得大一点,int数组默认是0.
        int[] number = new int[1000010];//辅助数组
        String s = scanner.nextLine();
        String[] str = s.split(" ");//分割数据

        for (int i = 0; i < n; i++) {
            arr[i] = Integer.parseInt(str[i]);//得到每一个数据
            number[arr[i]+500000]+=1;//建立辅助数组以500000为基准0来判断正负号
        }
        System.out.println();
        for (int i = 0; i < 1000010; i++) {
            if(number[i]>0&&i-500000>=m){
                System.out.println(i-500000);
            }
        }
    }
}

emm。基本思路一样,主要重点就是scanner的特性和Integer.parseInt()的方法。
我这里输出的是小于m的从小到大的的数据,题目要求是从大到小的m个数据。偷个懒嘿嘿嘿。只需要把范围并逆序查找即可。

多组数据的话再封装一下类就好啦,不过我估计java应该不会有多组数据,或者就是只需要写方法传参数即可。


在这里插入图片描述


例题

这里我们回忆一下归并排序
在这里插入图片描述

static void MergeSort(int[] arr, int left, int right) {
        if (left < right) {
            int middle = (left + right) / 2;//中间值

            MergeSort(arr, left, middle);
            MergeSort(arr, middle + 1, right);
            //排序
            merge(arr, left, middle, right);
        }


    }

    static void merge(int[] arr, int left, int middle, int right) {
            //分别计算两个分组的长度
            int n1 = middle - left + 1;
            int n2 = right - middle;

        //创建两个辅助数组
        int[] L = new int[n1];
        int[] R = new int[n2];

        //将原数组的元素拷贝到辅助数组中
        for (int i = 0; i < n1; i++) {
            L[i] = arr[left + i];
        }
        for (int j = 0; j < n2; j++) {
            R[j] = arr[middle+1+j];
        }

        //遍历两个数组,当其中任意一个数组遍历完毕的时候停止循环
        int i = 0,j = 0;
        int k = left;
        while (i<n1 && j<n2){

            if (L[i]<=R[j]){
                //当遍历到的左边数组元素小于等于遍历到右边的数组,原数组对应位置换为左边数组遍历到的值
                arr[k] = L[i];
                i++;
            }else {
                //当遍历到的左边数组元素大于遍历到右边的数组,原数组对应位置换为右边数组遍历到的值
                arr[k] = R[j];
                j++;
            }
            k++;
        }

        //将剩余的数组追加到原数组的尾部
        while (i < n1){
            arr[k] = L[i];
            i++;
            k++;
        }
        while (j < n2){
            arr[k] = R[j];
            j++;
            k++;
        }
    }

在这里插入图片描述

好啦,这上面就是一套标准的归并排序啦。
就是归并的时候稍微复杂一点。不过稍微分析一下来时很好办的。

例题 第k大的数

简单分析一下,第k大是从大到小排列的。
这里来说,需要nlogn的时间排序,再经过一次常数级别的查找。(这里只求第k大,所以没必要排序其他数据,并不关心)
这里用快速排序的思想,就能在O(n)级别内,查到数据。
快速排序的思想:
每次先将所有的值中,任意挑选值为中心值,所有小于4的放左边,比4大的放右边。
在这里插入图片描述
每次不变换左右的位置。
然后优化的部分就是,每次算出后,如果另外一边大于或小于目标数,则只算一边

    static void QuickSort(int arr[], int low, int high) {
        int i;//左边
        int j;//右边
        int temp;//基准位
        int t;
        if (low > high) {
            return;
        }
        i = low;
        j = high;
        //temp就是基准位
        temp = arr[low];

        while (i < j) {
            //先看右边,依次往左递减
            while (temp <= arr[j] && i < j) {//比temp大的不管,让j停留在第一个比temp小的。
                j--;
            }
            //再看左边,依次往右递增
            while (temp >= arr[i] && i < j) {//比temp小的不管,让i停留在第一个比temp大的。
                i++;
            }
            //每次只找到第一个满足条件的就跳出来,然后交换,先从右边,再从左边

            //如果满足条件则交换
            if (i < j) {
                t = arr[j];
                arr[j] = arr[i];
                arr[i] = t;
            }

        }
        //以下全为i==j
        //最后将基准位与i和j相等位置的数字交换
        arr[low] = arr[i];
        arr[i] = temp;
        //递归调用左半数组
        QuickSort(arr, low, j - 1);
        //递归调用右半数组
        QuickSort(arr, j + 1, high);

    }

这一部分是标注快排算法。
对于题目来说还有优化的地方
也就是最后一部分
此时,我们仅仅算一半就好了,对该题目从时间复杂度O(nlogn)下降为O(n)的时间复杂度

		if(k<i){
            //递归调用左半数组
            QuickSort(arr, low, j - 1);
        }
       if(k<i)
        //递归调用右半数组
        QuickSort(arr, j + 1, high);

       if(k==i){
           System.out.println(arr[i]);
       }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值