链表排序之快排与归并(递归与非递归)

news/2024/5/20 0:36:06 标签: 链表, 算法, 数据结构, 快速排序, 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.test;

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

public class Test {

	public static void fun1(List<Integer> arr, int left, int right) {
		Stack<Integer> stack = new Stack<Integer>();
		if (left < right) {
			stack.add(left);
			stack.add(right);
			while (!stack.isEmpty()) {
				int ri = stack.pop();
				int le = stack.pop();
				int k = quickSort1(arr, le, ri);
				if (le < k - 1) {
					stack.push(le);
					stack.push(k - 1);
				}
				if (ri > k + 1) {
					stack.push(k + 1);
					stack.push(ri);
				}

			}
		}
	}

	public static int quickSort1(List<Integer> list, int left, int 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);
		}
		return i;
	}

	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 = { 1, 3, -5, 7, -9, -8, -4, -3, -777 };
		long startTime = System.currentTimeMillis();
		LinkedList<Integer> linkedList = new LinkedList<>();
		for (Integer i : arr) {
			linkedList.add(i);
		}
		fun1(linkedList, 0, linkedList.size() - 1);
		System.out.println(linkedList);
		System.out.println("耗时:" + (System.currentTimeMillis() - startTime));
		//[-777, -9, -8, -5, -4, -3, 1, 3, 7]
		//		耗时:3
	}

}

递归:

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/1847079.html

相关文章

汪国真语录

没有比脚更长的路&#xff0c;没有比人更高的山 《山高路远》 我不去想是否能够成功&#xff0c;既然选择了远方&#xff0c;便只顾风雨兼程 《热爱生命》 假如你不够快乐&#xff0c;也不要把眉头深锁&#xff0c;人生本来短暂&#xff0c;为什么还要栽培苦涩 《假如我不够快…

实现折叠功能

2019独角兽企业重金招聘Python工程师标准>>> 首先&#xff0c;少说废话&#xff0c;上页面。 今天和大家分享下网页折叠功能的制作过程。 首先就是用div来画界面。我的代码如下&#xff1a; <% page language"java" contentType"text/html; chars…

用JAVA写的一个简单的图形界面计算器

一个简单的计算器&#xff0c;老师布置的作业。 用的swing和awt&#xff0c;bug还是有的&#xff0c;想起来了&#xff0c;发上来&#xff0c;自己留着收藏。 /*** Created by YunFeng on 2014/12/6 0009.* Student Number&#xff1a;* Teacher:Yongfeng Huang * University:…

JVM的Eden由来

JVM&#xff08;PART II&#xff09;Eden Survivor名称由来 Eden: 含义&#xff1a;伊甸园&#xff08;The garden of Eden&#xff09; Survivor&#xff1a; 含义&#xff1a;幸存者 GC&#xff1a; 含义&#xff1a;Garbage Collection Stop the world event 含义&a…

[JS-DOM BOM学习笔记]网页轮播图(已完结)

网页轮播图功能需求&#xff1a;案例分析显示隐藏display按钮动态生成小圆圈小圆圈的排他思想点击小圆圈滚动图片点击右侧按钮一次&#xff0c;就让图片滚动一张点击右侧按钮&#xff0c;小圆圈跟随变化自动播放功能节流阀轮播图也称为焦点图&#xff0c;是网页中比较常见的网页…

VS2017如何创建c语言项目

VS2017如何创建c语言项目 1.启动VS2017&#xff0c;左上角点“文件”→→→新建”→→→“项目” 或者用快捷键“CrtlshiftN” 2.选择“Windows桌面”→→→“Windows桌面向导”&#xff0c;名称部分自己改 3.弹出对话框后&#xff0c;在“空项目”前打对勾&#xff0c;再点“…

VS2017的一些调试方法技巧

VS2017的一些调试方法技巧 一、基本的操作。 1、启动调试。 可以通过VS的调试&#xff08;Debug&#xff09;菜单启动调试。点击调试菜单下的“启动调试”或者按F5键启动。如果你已经在代码中加入了断点&#xff0c;那么执行会自动开始。 注&#xff1a;退出调试快捷键shif…

经典算法_杨辉三角,集合法

经典算法_杨辉三角&#xff0c;集合法 代码编写环境:VSCode2017 杨辉三角: #include<stdio.h>int main() {int a[10][10];int i,j;//1、给二维数组赋初值for (i 0; i < 10; i){for (j 0; j < i; j){a[i][j] 0;}}//2、给二维数组的第一列和对角线赋值1for (i 0…