链表排序之快排与归并

news/2024/5/19 21:29:00 标签: 链表, 数据结构, 快速排序, java, 算法

链表排序之快排与归并




1.对链表进行快速排序

以【4,2,5,3,7,9,0,1】为例,我们来模拟一趟快排的过程。

1、 初始化时,i指向链表首元素4;j = i +1,指向2。基准数字为当前i 指向的数字:4。

j
42537901
i

2、 随后开始循环,j 当前指向2,因为2小于4,所以要把2移动到前面去。按照我们的算法步骤操作:

  • i ++,首先 i 向后移动一位,指向2
  • swap(i, j) ,随后交换 i、j 位置的值,这里面是2和2自己交换
  • j ++,然后 j 向后移动一位,指向5

执行一次交换后的结果如下:

j
42537901
i

3、 接下来,由于 j 指向的值5 大于4,直接跳过,执行j++,此时 j 指向3

j
42537901
i

4、 j 指向的值为3,小于4,仿照步骤2,我们再次执行一次交换移动过程。

  • i ++,首先 i 向后移动一位,指向5
  • swap(i, j) ,随后交换 i、j 位置的值,这里面是5和3交换
  • j ++,然后 j 向后移动一位,指向7

交换后的结果如下:

j
42357901
i

5、 j指向的值为7,大于4,所以直接跳过,执行 j++,j 指向9

j
42357901
i

6、 同理,j 指向的值为9,也大于4,跳过,执行 j++,j 指向0

j
42357901
i

7、 j 指向的值为0,小于4,执行一次交换过程

  • i ++,首先 i 向后移动一位,指向5
  • swap(i, j) ,随后交换 i、j 位置的值,这里面是5和0交换
  • j ++,然后 j 向后移动一位,指向1

交换后的结果如下:

j
42307951
i

8、 j 指向的值为1,小于4,我们再执行一次交换过程

  • i ++,首先 i 向后移动一位,指向7
  • swap(i, j) ,随后交换 i、j 位置的值,这里面是7和1交换
  • j ++,然后 j 向后移动一位,已经超过了链表的长度,不再向后移动。

交换后的结果如下:

j
42301957
i

9、 最后,交换当前 i指向的值1,和4。得到【1、2、3、0、4、9、5、7】,一趟排序结束。

j
12304957
i

我们发现,4的左边都是小于4的数字,右边都是大于4的数字。
接下来,对左边和右边分别排序,不断递归下去,直到元素全部有序。


代码如下:

java">package com.m.suan_pai;


import java.util.LinkedList;
import java.util.List;

public class Test {

    public static void QuickSort1(List<Integer> list, int left, int right) {
        if (left < right) {
            dealPivot1(list, left, right);

            int pivot = right - 1;
            int i = left;
            int j = pivot;

            while (true) {
                while (list.get(++i) < list.get(pivot)) {
                }
                while (j > left && list.get(--j) > list.get(pivot)) {
                }
                if (i < j) {
                    swap1(list, i, j);
                } else {
                    break;
                }
            }
            if (i < right) {
                swap1(list, i, right - 1);
            }
            dealPivot1(list, left, i - 1);
            dealPivot1(list, i + 1, right);
        }
    }

    public static void dealPivot1(List<Integer> list, int left, int right) {
        int mid = (left + right) / 2;
        if (list.get(left) > list.get(right)) {
            swap1(list, left, right);
        }
        if (list.get(left) > list.get(mid)) {
            swap1(list, left, mid);
        }
        if (list.get(mid) > list.get(right)) {
            swap1(list, mid, right);
        }

        swap1(list, mid, right - 1);
    }

    public static void swap1(List<Integer> list, int a, int b) {
        int t = list.get(a);
        list.set(a, list.get(b));
        list.set(b, t);
    }

    public static void main(String[] args) {
        int[] arr = new int[]{34, 56, 3, 43, 54, 23, 42};

        LinkedList<Integer> linkedList = new LinkedList<>();
        for (Integer i : arr) {
            linkedList.add(i);
        }
        QuickSort1(linkedList, 0, linkedList.size() - 1);
        System.out.println(linkedList);
    }


}



快排不适合同于链表,但是可以实现,时间复杂度为o(nlgn)

平均时间复杂度O(nlogn),不考虑递归栈空间的话空间复杂度是O(1))

分析:由于单链表是没有prev指针的,所以跟数组一样的low,high指针就不适合单链表




链表进行归并排序


我们对链表进行排序,使用归并排序来进行排序,时间复杂度O(nlgn)。

此种方式的排序主要涉及到以下三个知识点:

  1. 两个链表的归并;

  2. 归并排序的思想;

  3. 获取一个链表的中间结点;

我的归并排序代码如下

java">package com.m.suan_pai;


import java.lang.reflect.InvocationTargetException;
import java.util.LinkedList;
import java.util.List;

public class Test {

    public static void mergeSort(List<Integer> list) {
        try {

            List<Integer> list1 = list.getClass().getConstructor().newInstance();

            mergeSort(list,0,list.size()-1,list1);

        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
    }

    public static void mergeSort(List<Integer> list, int left, int right, List<Integer> list2) {
        if(left < right){
            int mid = (left+right)/2;

            //使左子树有序
            mergeSort(list,left,mid,list2);

            //使右子树有序
            mergeSort(list,mid+1,right,list2);

            //合并左右子树
            merge(list,left,mid,right,list2);
        }
    }

    public static void merge(List<Integer> list, int left, int mid,int right, List<Integer> list2) {
        int index = 0;
        int i = left;
        int j = mid+1;

        while (i<=mid && j<=right){
            if(list.get(i)<list.get(j)){
                list2.add(index++,list.get(i++));
            }else{
                list2.add(index++,list.get(j++));
            }
        }

        while (i<=mid){
            list2.add(index++,list.get(i++));
        }

        while (j<=right){
            list2.add(index++,list.get(j++));
        }

        index = 0;

        while (left <= right){
            list.set(left++,list2.get(index++));
        }
    }

    public static void main(String[] args) {
        int[] arr = new int[]{34, 56, 3, 43, 54, 23, 42};

        LinkedList<Integer> linkedList = new LinkedList<>();
        for (Integer i : arr) {
            linkedList.add(i);
        }
        mergeSort(linkedList);
        System.out.println(linkedList);
    }


}




http://www.niftyadmin.cn/n/1847119.html

相关文章

2019牛客暑期多校训练营(第十场)D Han Xin and His Troops(Java大数+扩展中国剩余定理模板)

链接&#xff1a;https://ac.nowcoder.com/acm/contest/890/D 题意&#xff1a;求同余方程组。 思路&#xff1a; import java.math.BigInteger; import java.util.Scanner;public class Main {public static int N 100010;public static BigInteger a[] new BigInteger[N…

[JS-DOM BOM学习笔记]DOM那些儿事儿3

[JS-DOM BOM学习笔记]DOM那些儿事儿节点操作创建节点添加节点1.node.appendChild(child)2.node.insertBefore(child,指定元素)创建节点添加节点代码案例删除节点复制节点(克隆节点)三种动态创建元素区别节点操作 创建节点 document.createElement(tagName)方法创建由tagName指…

进程间通信的方式有哪些?

进程间通信的方式有哪些&#xff1f; 1、进程间通讯方式有&#xff1a;管道&#xff0c;信号&#xff0c;信号量&#xff0c;消息队列&#xff0c;共享内存&#xff0c;套接字共六种 2、管道&#xff1a;管道分为有名管道和无名管道&#xff0c;其中无名管道是一种半双工的通…

2019牛客暑期多校训练营(第十场)F Popping Balloons(思维)

链接&#xff1a;https://ac.nowcoder.com/acm/contest/890/F 题意&#xff1a;n个气球&#xff0c;横着打3枪竖着打3枪&#xff08;横着打的相邻两枪之间的间隔和竖着打的相邻两枪间隔都要等于r。&#xff09;。求最多能打多少气球。同一个位置可能有多个气球。 思路&#x…

使用echarts问题1

如果如果你是这样使用echarts的&#xff0c;那请注意了。 刚开始我用页面的DOM去做echarts.init(dom)&#xff1b; 然后再用cloneDom $(dom).clone().attr(id, newId); 去做echarts.init(cloneDom);这样就会发现所有的内容都绘制到第二个图例中去了。 这是因为DOM和cloneDom的…

[机器学习的模型评估很难吗!?]生成ROC,PR,混淆矩阵(给你打包成函数了0.T)

生成ROC,PR,混淆矩阵写在前面ROC曲线生成代码有关汽车评估roc曲线没有梯度的原因PR曲线生成代码同样地&#xff0c;对比在不同叶子纯度的情况的PR图混淆矩阵生成代码想看不同模型之间的Friedman检验吗?写在前面 汽车评估 机器学习 第十四组 “人见人爱&#xff0c;花见花开&a…

Linux下清空缓冲区的方法

Linux下清空缓冲区的方法C标准规定fflush()函数是用来刷新输出&#xff08;stdout&#xff09;缓存的。对于输入&#xff08;stdin&#xff09;&#xff0c;它是没有定义的。但是有些编译器也定义了fflush( stdin )的实现&#xff0c;比如微软的VC。其它编译器是否也定义了fflu…

BZOJ3331: [BeiJing2013]压力(点双连通分量+缩点+LCA+树上差分)

链接&#xff1a;https://www.lydsy.com/JudgeOnline/problem.php?id3331 题意&#xff1a;n个点&#xff0c;m条无向边&#xff0c;给出q个点对&#xff0c;问这n个点分别是多少点对的必经点。&#xff08;两点本身也算也算。&#xff09; 思路&#xff1a;显然&#xff0c…