【JAVA】数据结构——堆的排序及相关面试题

本文详细介绍了多种排序算法,包括冒泡排序、插入排序、希尔排序、选择排序、堆排序、快速排序(递归与非递归优化)、归并排序(递归与非递归)以及计数排序。每种算法都提供了Java实现,并分析了它们的时间复杂度、空间复杂度和稳定性。此外,还探讨了Top K问题的解决方案。测试数据运行时间显示了不同排序算法在有序和无序数据上的性能差异。
摘要由CSDN通过智能技术生成

目录

1.堆的排序

2.直接插入排序

3.希尔排序(缩小增量法)

4.选择排序

5.堆排序

6.冒泡排序

7. 快速排序

7.1未优化快速排序:递归完成

7.2 优化快速排序: (三数取中) 非递归分治 --> 不会堆溢出 

7.3  非递归  快速排序:  

8.   归并排序 

8.1 递归实现 归并排序 

8.2  归并排序   ---->非递归排序 

9. 合并两个有序数组  

10.    计数排序:  

 11.topK问题

面试题1:查找和最小的 K 对数字

11.测试数据运行时间


1.大小堆的创建、如何放元素、获取队头元素:

【JAVA】数据结构——优先级队列(堆的应用)

基于比较的排序方法:

排序方法最好平均最坏空间复杂度稳定性
冒泡排序O(n)O(n^2)O(n^2)O(1)稳定
插入排序O(n)O(n^2)O(n^2)O(1)稳定
选择排序O(n^2)O(n^2)O(n^2)O(1)不稳定
希尔排序O(n)O(n^1.3)O(n^1.5)O(1)不稳定
堆排序O(n * log(n))O(n * log(n))O(n * log(n))O(1) 不稳定
快速排序 O(n * log(n))O(n * log(n))O(n^2)O(log(n)) ~ O(n) 不稳定
归并排序  O(n * log(n))O(n * log(n))O(n * log(n))O(n)稳定

稳定的排序方式:冒泡、直接插入、归并排序

冒泡、选择、直接插入排序都是比较简单的排序,

1.堆的排序

升序,则创建大根堆


/*从小到大排序:
1. 调整为大根堆
2. 0下标和最后一个未排序的元素进行交换
3. end-- 
* */
    public void heapSort() {
        int end = usedSize-1;
        while (end > 0) {
            int tmp = elem[0];
            elem[0] = elem[end];
            elem[end] = tmp;
            shiftDown(0,end);  //向下调整
            end--;
        }
    }

2.直接插入排序

时间复杂度: O(N^2) --》最好的情况O(N):数据有序
空间复杂度: O(1)
稳定性: 稳定
若一个本身就不稳定的排序,是不会变成稳定的排序的


public class testSorts {

    public static void insertSort(int[] array) {
        for (int i = 1; i < array.length; i++) {
            int tmp = array[i]; //开辟一块内存tmp存放从第二个元素开始的array[i]元素
            int j = i-1;  //j始终在i的前一个位置
            for (; j >= 0 ; j--) {
                if (array[j] > tmp) { //如果j下标大于tmp的值,则将array[j]往后移(升序)
                    array[j+1] = array[j];  //也即是ij对应元素互换
                }else {  //不大于(<=)就不移动,默认是升序排列,退出此步操作
//                    array[j+1] = tmp;
                    break; //只要j回退到比tmp小的元素就结束这次比较
                }
            }//j为负数时候
            //j回退到小于0的地方
            array[j+1] = tmp;
        }
    }

3.希尔排序(缩小增量法)

分组,组内是直接排序(是对直接插入排序的优化)

希尔排序法的基本思想是:先选定一个整数,把待排序文件中所有记录分成个组,所有距离为的记录分在同一组内,并对每一组内的记录进行排序。然后,重复上述分组和排序的工作。当到达=1时,所有记录在统一组内排好序。
1. 希尔排序是对直接插入排序的优化。
2. 当gap > 1时都是预排序,目的是让数组更接近于有序。当gap == 1时,数组已经接近有序的了,这样就会很快。

 时间复杂度【和增量有关系】:O(N^1.3到N^1.5)最好和最坏 --》最好的情况O(N):数据有序
 空间复杂度:O(1)
 稳定性:不稳定
 交换过程中若发生跳跃式交换,则是不稳定的 


// gap:组数         array:待排数列
    public static void shell(int[] array,int gap) {  //此函数shell也即是直接插入排序方法
        for (int i = gap; i < array.length; i++) { //i从下标为gap的值开始
            int tmp = array[i];
            int j = i-gap;
            for (; j >=0; j -= gap) {
                if (array[j] > tmp) { //tmp是i处的值,j在左边,而array[j]值更大,说明不是有序的,需要更换位置
                    array[j+gap] = array[j]; //j+gap也即是i,此处为交换ij对应元素
                }else {   //如果值符合要求,则位置不变动,退出此次循环即可,继续下一步的循环:i+1
                    break;
                }
            }
            array[j+gap] = tmp;  //j < 0,  tmp不变化,也即是将i放回原位置
        }
    }

    public static void shellSort(int[] array) {
        int gap = array.length;
        while (gap > 1) {      //进行分组,预排序
            shell(array,gap);
            gap /=2;
        }
        shell(array,1); //保证最后是一组

    }

4.选择排序

保持第一个元素不动,后续元素依次与此进行大小比较,后面值小的话进行位置交换

时间复杂度【和增量有关系】: O(N^2)  对数据不敏感
空间复杂度:  O(1)
稳定性: 不稳定

    public static void swap(int[] array,int i,int j) {
        int tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }

    public static void selectSort1(int[] array) {
        for (int i = 0; i < array.length; i++) {
            for (int j = i + 1; j < array.length; j++) {
                if(array[i] > array[j]) {   //升序排列 降序排列:array[i] < array[j]
                    swap(array,i,j);
                }
            }
        }
    }

//优化选择排序
    public static void selectSort(int[] array) {
        for (int i = 0; i < array.length; i++) {
            int minIndex = i;
            for (int j = i + 1; j < array.length; j++) {
                if (array[j] < array[minIndex]) {
                    minIndex = j;
                }
            }
            swap(array,i,minIndex);
        }
    }


5.堆排序

升序(从小到大):建立大根堆

基本原理:选择排序,但不使用遍历的方式,而是通过堆来选择查找无序区间的最大的数

 时间复杂度:O(N*log2(N))
 空间复杂度: O(1)
稳定性: 不稳定

解析:

1.先创建大根堆createHeap
2.0下标和end下标交换
3.继续调整当前堆为大根堆shiftDown
4.end--,继续交换

    public static void heapSort(int[] array) { //堆排序
        createHeap(array); //首先创建大根堆---->0下标和最后一个下标end(array.leng-1)进行位置交换
        int end = array.length-1;  //end为最后一个元素下标
        while (end > 0) { //循环条件:end 》 0,当end走到0下标时完成交换
            swap(array,0,end); //进行交换,交换结束之后调整为大根堆
            shiftDown(array,0,end); //调整为大根堆之后,根节点依旧是除开end之外的最大值
            end--; //此时再继续进行交换(end和0),继续循环
        }
    }
    public static void createHeap(int[] array) {
        //child = array.length-1;
        //大根堆parent往后走,最初只会知道最后一个孩子的下标array.length-1,由此可得对应parent
        for (int parent = (array.length-1-1)/2; parent >= 0 ; parent--) {
            shiftDown(array,parent,array.length);  //大根堆:向下调整,
        }
    }
    public static void shiftDown(int[] array,int parent,int len) {
        int child = 2*parent+1;   //左孩子
        while (child < len) {  //循环条件:孩子child下标在数组长度范围内
            //child+1 < len说明至少有一个右孩子--》array[child] < array[child+1]表明右孩子更大,
            if (child+1 < len && array[child] < array[child+1]) { //此处child+1是右孩子,没有超过数组长度len,且左孩子<右孩子
                child++; //变为最后一个孩子,且右孩子大于左孩子
            }
            //child下标是左右孩子最大值的下标
            if (array[child] > array[parent]) { //如果孩子对应值>父亲节点,则进行交换(保持根(父亲)节点>孩子)
                swap(array,child,parent);
                parent = child;  //交换之后继续往后走,父亲节点走到子节点位置,而子节点继续向后走
                child = 2*parent+1;
            }else {  //孩子节点不大于父亲节点,则不用交换,退出break即可
                break;
            }
        }
    }

6.冒泡排序

在无序区间,通过相邻数的比较,将最大的数冒泡到无序区间的最后,持续这个过程,直到数组整体有序

时间复杂度】:O(N^2)
空间复杂度:O(1)
稳定性:稳定


//========================未优化冒泡排序:====================================//

    public static void bubbleSorts0(int[] array) {
        for (int i = 0; i < array.length-1; i++) {
            for (int j = 0; j < array.length-1-i; j++) { //每一次会确定一个有序值放在最后,因此,j的长度每次也会减少
                if (array[j] > array[j+1]) {
                    swap(array,j+1,j);
                }
            }
        }
    }
//========================优化冒泡排序:====================================//
//2.时间复杂度】:最坏O(N^2)  最好O(N)
    public static void bubbleSorts(int[] array) {
        for (int i = 0; i < array.length-1; i++) {
            boolean isSorted= false;
            for (int j = 0; j < array.length-1-i; j++) { //每一次会确定一个有序值放在最后,因此,j的长度每次也会减少
                if (array[j] > array[j+1]) {
                    swap(array,j+1,j);
                   isSorted = true;
                }
            }
            if (isSorted == false) {
                break;
            }
        }
    }

7. 快速排序

7.1未优化快速排序:递归完成

时间复杂度】:最坏O(N^2)  最好O(N*log2(N))
空间复杂度:O(N)
稳定性:不稳定

 解析:

1.选择基准,将第一个元素存放到tmp,从后往前找,若比tmp大,end--,继续往前寻找,不变换位置;若比tmp小的值放到第一个位置start下标处;
2.然后从start开始遍历,找>tmp的值,将其放入到end--停留的位置处
3.继续执行上述操作,继续找比基准元素tmp大或者小元素并移动位置,----》左边的值<基准,右边>基准。
4.继续将第一个元素作为基准元素,重复上述操作

//start:起始下标    end:最后一个元素下标    pivot:基准下标   
  //1.找基准元素 :
    public static int partition(int[] array, int start, int end)  {//找基准的函数
        int tmp = array[start]; // 基准找完之后从后找
        while (start < end) {
            while (start < end && array[end] >= tmp) { //比基准元素大,则不移动该元素,向前找end--
                end--;
            }
            //走完之后end下标遇到 < tmp的值
            array[start] = array[end];  //遇到的值<tmp,则将其放入start位置
            while (start < end && array[start] <= tmp) {
                start++; //array[start] 小于基准tmp元素,则不移动,继续向前遍历,start++
            }
            //当array[start] > tmp,则向后移动到 上一步的end的位置
            array[end] = array[start];
        }
        array[start] = tmp; //start 和end相遇,将tmp放到这个位置,至此/第一次循环结束,得到基准元素左边的值小于基准,右边的值大于基准,
        return start; //返回start或者end,也即是相遇的位置
    }

//找到基准元素之后,对其左右进行排序
    public static void quick0(int[] array,int left,int right) { //类似二叉树,分而治之,先找到基准,然后执行左边和右边
        if (left >= right) { //当左右相遇的时候,退出递归,直接return。
            return;
        }//退出之后继续找第一个元素作为基准
        int pivot = partition(array,left,right);//先找到基准,在分别递归左边和右边
        quick(array,left,pivot-1);
        quick(array,pivot+1,right);
    }

    public static void quickSort0(int[] array) {  //快速排序:完成对一个数组的排序
        quick(array,0, array.length-1);// 对数组array,从下标0到array.length-1进行排序--》快速排序也即是递归quick的一个过程
    }

   

7.2 优化快速排序: (三数取中) 非递归分治 --> 不会堆溢出 


时间复杂度】:最坏O(N^2)  最好O(N)
空间复杂度:O(1)
稳定性:不稳定

解析:

1.选择基准,将第一个元素存放到tmp,从后往前找,若比tmp大,end--,继续往前寻找,不变换位置;若比tmp小的值放到第一个位置start下标处;
2.然后从start开始遍历,找>tmp的值,将其放入到end--停留的位置处
3.继续执行上述操作,继续找比基准元素tmp大或者小元素并移动位置,----》左边的值<基准,右边>基准。
4.继续将第一个元素作为基准元素,重复上述操作


    private static int findMidValIndex(int[] array,int start,int end) {
        int mid = start + ((end - start) >>> 1);  // >>> 1:右移1位--》也即是除2
        if (array[start] < array[end]) {
            if (array[mid] < array[start]) {
                return start;
            } else if (array[mid] > array[end]) {
                return end;
            } else {
                return mid;
            }
        }else {
            if (array[mid] > array[start]) {
                return start;
            } else if (array[mid] < array[end]) {
                return end;
            }else {
                return mid;
            }
        }
    }

    public static void quick(int[] array,int left,int right) { //类似二叉树,分而治之,先找到基准,然后执行左边和右边
        if (left >= right) { //当左右相遇的时候,退出递归,直接return。
            return;
        }
        //1.如果区间内的数据在排序过程中,如果小于某个范围(如40),则可直接进行直接插入排序
        if (right-left+1 <=40) {
            insertSort(array);
            return;
        }
        //2.退出之后继续找中间元素作为基准(三数取中)
        int midValIndex = findMidValIndex(array,left,right);
        swap(array,left,right);

        int pivot = partition(array,left,right);//先找到基准,在分别递归左边和右边
        quick(array,left,pivot-1);
        quick(array,pivot+1,right);
    }

    public static void quickSort(int[] array) {  //快速排序:完成对一个数组的排序
        quick(array,0, array.length-1);// 对数组array,从下标0到array.length-1进行排序--》快速排序也即是递归quick的一个过程
    }



7.3  非递归  快速排序:  

解析:

1.找基准
2.借用栈 --》放入左区间下标、和右区间下标-->相对于基准的左右(四个下标值)--》前提是基准pivot左右都有俩元素
3.弹出栈顶两个元素,也即是右边区间的两个下标
4.然后再弹出的两个下标区间内找基准:第一个下标元素放入tmp,从最后一个下标往前依次与tmp比较,  当后面的值比tmp小时,则将其移动到弹出区间的第二个位置


    public static void quickSorts(int[] array) {
        Stack<Integer> stack = new Stack<>();
        int left = 0;
        int right  = array.length-1;
        int pivot = partition(array,left,right);
        if (pivot > left+1) { //说明左边有至少俩元素
            stack.push(left);  //将左边下标放入堆里
            stack.push(pivot-1);
        }
        if (pivot < right-1) { //说明右边边有至少俩元素
            stack.push(pivot+1);  //将右边下标放入堆里
            stack.push(right);
        }
        //查看栈是否为空,不为空执行以下循环:弹出两个元素作为左右下标继续找基准
        while (!stack.isEmpty()) {
            right  = stack.pop();
            left = stack.pop();
            pivot = partition(array,left,right);

            if (pivot > left+1) { //说明左边有至少俩元素
                stack.push(left);  //将左边下标放入堆里
                stack.push(pivot-1);
            }
            if (pivot < right-1) { //说明右边边有至少俩元素
                stack.push(pivot+1);  //将右边下标放入堆里
                stack.push(right);
            }
        }
    }

 //1.找基准元素 :
    public static int partition(int[] array, int start, int end)  {//找基准的函数
        int tmp = array[start]; // 基准找完之后从后找
        while (start < end) {
            while (start < end && array[end] >= tmp) { //比基准元素大,则不移动该元素,向前找end--
                end--;
            }
            //走完之后end下标遇到 < tmp的值
            array[start] = array[end];  //遇到的值<tmp,则将其放入start位置
            while (start < end && array[start] <= tmp) {
                start++; //array[start] 小于基准tmp元素,则不移动,继续向前遍历,start++
            }
            //当array[start] > tmp,则向后移动到 上一步的end的位置
            array[end] = array[start];
        }
        array[start] = tmp; //start 和end相遇,将tmp放到这个位置,至此/第一次循环结束,得到基准元素左边的值小于基准,右边的值大于基准,
        return start; //返回start或者end,也即是相遇的位置
    }

8.   归并排序 

8.1 递归实现 归并排序 

归并排序:是建立在归并操作上的一种有效的排序算法,采用分治法。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。

将两个有序表合并成一个有序表,称为二路归并。

时间复杂度】:O(N*log(N))
空间复杂度:O(N)
稳定性:稳定  若(array[s1] <= array[s2],不取等号则是不稳定的


    public static void merSort(int[] array) {  //合并有序的两个数组
        mergeSortInternal(array,0,array.length-1);
    }
    public static void mergeSortInternal(int[] array,int low,int high) {
        if (low >= high) {
            return;
        }
        int mid = low + (high-low) >>>1;  //(low+high)/2

        mergeSortInternal(array,low,mid); //左边
        mergeSortInternal(array,mid+1,high); //右边
        merge(array,low,mid,high);//合并
    }
    public static void merge(int[] array,int low,int mid,int high){  //合并两个有序数组:二路归并
        int[] array3 = new int[high-low+1];//创建一个新数组用于存放元素
        int k = 0;  //k为新数组下标
        int s1 = low;  //有序数组1
        int e1 = mid;

        int s2 = mid+1;  //有序数组2
        int e2 = high;

        while (s1 <= e1 && s2 <= e2) {
            if (array[s1] <= array[s2]) {  //比较两个有序数组第一个元素的大小,小的元素放入新数组
                array3[k++] = array[s1++];
            }else {  // 另一个数组元素小 array2[s2] < array1[s1]
                array3[k++] = array[s2++];
            }
        }
        while (s1 <= e1) {  //此时说明第一个数组还剩下数据没移动到新数组,直接将其放入到新数组即可
            array3[k++] = array[s1++];
        }
        while (s2 <= e2) {
            array3[k++] = array[s2++];
        }
        //拷贝array数组元素,放入原数组
        for (int i = 0; i < k; i++) {
            array[i+low] = array3[i];
        }
    }

8.2  归并排序   ---->非递归排序 

时间复杂度】:O(N*log(N))
空间复杂度:O(N)
稳定性:稳定  若(array[s1] <= array[s2]不取等号则是不稳定的

    //定义i下标遍历数组
    public static void merSort1(int[] array) {  //合并有序的两个数组
        int gap = 1;
        int nums = 1;
        while (gap < array.length) {
            //每次都要对数组进行遍历
            for (int i = 0; i < array.length; i +=nums*2) {
                int left = i;
                int mid = left+nums-1;
                if (mid >= array.length) { //防止越界
                    mid = array.length-1;
                }
                int right = mid+nums;
                if (right >= array.length) {
                    right = array.length-1;
                }
                merge1(array,left,mid,right);
            }
            nums *=2;
        }
    }

    public static void merge1(int[] array,int low,int mid,int high){  //合并两个有序数组
        int[] array3 = new int[high-low+1];//创建一个新数组用于存放元素
        int k = 0;
        int s1 = low;
        int e1 = mid;

        int s2 = mid+1;
        int e2 = high;

        while (s1 <= e1 && s2 <= e2) {
            if (array[s1] <= array[s2]) {
                array3[k++] = array[s1++];
            }else {  // 另一个数组元素小 array2[s2] < array1[s1]
                array3[k++] = array[s2++];
            }
        }
        while (s1 <= e1) {  //此时说明第一个数组还剩下数据没移动到新数组,直接将其放入到新数组即可
            array3[k++] = array[s1++];
        }
        while (s2 <= e2) {
            array3[k++] = array[s2++];
        }
        //拷贝array数组元素,放入原数组
        for (int i = 0; i < k; i++) {
            array[i+low] = array3[i];
        }
    }

9. 合并两个有序数组  

  解析:

1.将两个有序数组合并为一个数组:定义两个数组的起始下标-->也即是(二路归并)
2.比较两个数组第一个元素的大小,将小的元素放入到一个新的数组,有小元素的数组继续向后走
3.将其的第二个元素与另一个数组的第一个元素进行比较,小的放入新的数组而各个位置;
4.重复以上2和3步骤---》若其中一个数组走完(下标超出length-1),直接将另一个数组剩下的的元素放入新数组即可,至此完成两个数组的合并


    public static int[] mergeArray(int[] array1,int[] array2) {
        int[] array3 = new int[array1.length+array2.length];//创建一个新数组用于存放元素
        int k = 0; //新数组下标
        int s1 = 0;  //数组1起始下标
        int e1 = array1.length-1;

        int s2 = 0; //数组2起始下标
        int e2 = array2.length-1;

        while (s1 <= e1 && s2 <= e2) { // 当两个数组都在下表范围内时,比较元素大小
            if (array1[s1] <= array2[s2]) {  //数组1更小则将其让如新数组
                array3[k++] = array1[s1++];
            }else {  // 数组2元素小 array2[s2] < array1[s1]
                array3[k++] = array2[s2++];
            }
        }
        //此时已经有一个数组走完,另一个数组还剩下元素,只需将剩下的直接放入新数组即可
        while (s1 <= e1) {  //此时说明第一个数组还剩下数据没移动到新数组,直接将其放入到新数组即可
            array3[k++] = array1[s1++];
        }
        while (s2 <= e2) {
            array3[k++] = array2[s2++];
        }
        return array3;
    }

10.    计数排序:  

适用于有N个数,数据范围:0-N之间 

解析:

1.先创建一个计数数组count[]用于存放每个数组中每个元素出现的次数-->count数组范围是原数组数据的最小值到最大值
2.求数组的最大值maxval和最小值minval--->maxval-minval+1=count[]数组长度
3.count[array[i]-minval]
    当前代码不稳定  但是计数排序的本质是稳定的


    public static void countingSort(int[] array) {
        int maxVal = array[0];
        int minVal = array[0];
        for (int i = 1; i < array.length; i++) {
            if (array[i] < minVal) {
                minVal = array[i];
            }
            if (array[i] > maxVal) {
                maxVal = array[i];
            }
        }
        //此时找到了最大值和最小值
        int[] count = new int[maxVal-minVal+1]; //默认都是0
        //统计每个数据出现的次数
        for (int i = 0; i < array.length; i++) {  //原数组的值作为新数组count的下标
            int index = array[i];//index为新数组count下标
            count[index-minVal]++; //计数
        }
        //此时说明计数数组中已经统计完每个数据出现的次数,后面只需遍历数组,将数据写出来即可,最后返回数组
        int indexArrray = 0; //定义一个新下标
        for (int i = 0; i < count.length; i++) {
            while (count[i] > 0) { //说明count[i]这里存放了数据出现的次数--》(count[i] 是数据i出现的次数
                array[indexArrray] = i+minVal; //一定要加minval,因为不一定就是i出现了count[i]
                count[i]--;//拷贝一次之后次数减少一个
                indexArrray++;//下标继续向后移动
            }
        }
    }

 11.topK问题

求解数组中前k个最小的元素--》大根堆完成

public class topK {
      public static int[] topK(int[] array,int k) {
//1.创建一个大小为k的大根堆
        PriorityQueue<Integer> maxHeap = new PriorityQueue<>(k, new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o2-o1;
            }
        });
//2.遍历数组中,前k个元素放到队列中
        for (int i = 0; i < array.length; i++) {
            if (maxHeap.size() < k) {
                maxHeap.offer(array[i]);//没超过k个元素,就继续往里面放元素
            }else {
//3.从第k+1个元素开始,每个元素与堆顶元素进行比较
                int top = maxHeap.peek(); //获取当前堆顶元素
                if (top > array[i]) { //如果当前元素<栈顶元素 ,
                    maxHeap.poll(); //弹出堆顶元素
                    maxHeap.offer(array[i]);  //存入堆顶元素
                }
            }
        }
        int[] tmp = new int[k];
        for (int i = 0; i < k; i++) {
            tmp[i] = maxHeap.poll();
        }
        return tmp;
    }

    public static void main(String[] args) {
        int[] array = {18,21,8,10,34,12};
        int[] tmp = topK(array,3);
        System.out.println(Arrays.toString(tmp));
    }
}



面试题1:查找和最小的 K 对数字

给定两个以 升序排列 的整数数组 nums1和nums2,以及一个整数 k
定义一对值 (u,v),其中第一个元素来自 nums1,第二个元素来自 nums2 。请找到  和最小的  k个数对 (u1,v1),  (u2,v2)  ...  (uk,vk) 。  list类型就可存放一对值

    public List<List<Integer>> kSmallestPairs(int[] nums1, int[] nums2, int k) {
        PriorityQueue<List<Integer>> maxHeap = new PriorityQueue<>(k, new Comparator<List<Integer>>() {
            @Override
            public int compare(List<Integer> o1, List<Integer> o2) {
                return (o2.get(0)+o2.get(1))-(o1.get(0)+o1.get(1));
            }
        });
        for (int i = 0; i < Math.min(nums1.length,k); i++) {
            for (int j = 0; j < Math.min(nums2.length,k); j++) {
                if (maxHeap.size() < k) {
                    List<Integer> tmpList = new ArrayList<>();
                    tmpList.add(nums1[i]);
                    tmpList.add(nums2[j]);
                    maxHeap.offer(tmpList);
                }else {
                    int top = maxHeap.peek().get(0) + maxHeap.peek().get(1);
                    if (top > nums1[i]+nums2[j]) {
                        maxHeap.poll();
                        List<Integer> tmpList = new ArrayList<>();
                        tmpList.add(nums1[i]);
                        tmpList.add(nums2[j]);
                        maxHeap.offer(tmpList);
                    }
                }
            }
        }
        List<List<Integer>> ret = new ArrayList<>();
        for (int i = 0; i < k && !maxHeap.isEmpty();i++) {
            ret.add(maxHeap.poll());
        }
        return ret;
    }

11.测试数据运行时间


    //========================测试有序数据运行时间==================================================//
    public static void testTime1(int capacity) {
        int[] array = new int[capacity];
        for (int i = 0; i < array.length; i++) {
            array[i] = i;
        }
        long start = System.currentTimeMillis();
        insertSort(array);
        shellSort(array);
        selectSort(array);
        long end  =System.currentTimeMillis(); //时间单位毫秒
        System.out.println(end-start);
    }

    public static void main0(String[] args) {
        testTime1(10_0000);  //1745  说明了有序的时间更快

        testTime2(10_0000);  //5598
    }

    //========================测试无序数据运行时间==================================================//
    public static void testTime2(int capacity) {
        int[] array = new int[capacity];
        Random random = new Random();
        for (int i = 0; i < array.length; i++) {
            array[i] = random.nextInt(capacity);
        }
        long start = System.currentTimeMillis();
        insertSort(array);
        shellSort(array);
        selectSort(array);
        quickSort(array);
        long end  =System.currentTimeMillis(); //时间单位毫秒
        System.out.println(end-start);
    }



    public static void main1(String[] args) {
        int[] array = {12,5,18,10,4,2};
        int[] array1 = {12,99,18,11,4,2};
//        insertSort(array);
//        shellSort(array1);
//        selectSort(array1);
//        heapSort(array);
//        bubbleSorts(array1);
        quickSort(array);
        quickSort(array1);
        System.out.println(Arrays.toString(array));
        System.out.println(Arrays.toString(array1));
    }

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值