IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 数据结构与算法 -> LeetCode 排序链表 -> 正文阅读

[数据结构与算法]LeetCode 排序链表

给你链表的头结点 head ,请将其按 升序 排列并返回 排序后的链表 。
在这里插入图片描述
在这里插入图片描述

1、暴力方法,先将链表的值存放到一个数组中,然后对这个数组进行快速排序,然后只需要遍历这个数组,将对应的数组的值赋值给链表的节点即可。但是这样做的话需要开辟空间给数组。
对应的代码:

class Solution {
    public ListNode sortList(ListNode head) {
       ListNode cur = head;
       List<Integer> list = new ArrayList<Integer>(); //临时存放链表的值
       while(cur != null){
           list.add(cur.val);
           cur = cur.next;
       }
       int[] arr = new int[list.size()];
       int i;
       for(i = 0; i < arr.length; i++){
           arr[i] = list.get(i);
       }
       sort(arr,0,arr.length - 1); //对数组进行快速排序
       /*
       遍历链表之后,重新创建链表的操作虽然也可以,但是这样的话就还需要
       开辟空间,所以为了减少空间的浪费,直接在原来的链表的基础上修改它
       节点的值即可。
       */
       cur = head;
       //遍历已经排好序的数组,然后构建链表
       for(i = 0; i < arr.length; i++){
           cur.val = arr[i];
           cur = cur.next;
       }
       return head;
    }
    public void sort(int[] arr,int low,int high){
        if(low < high){
            int pivot = getPivot(arr,low,high); //利用三数中值法,从而获取中间枢纽
            System.out.println(pivot);
            int i = low,j = high - 1;
            while(i < j){
            /*
            必须要从左边开始遍历,找到第一个大于枢纽的数,然后从右边遍历
            找到第一个小于枢纽的数,然后将两者的值进行交换。如果两个步骤
            交换顺序,那么就会导致快速排序的错误
            */
            
                while(i < j && arr[++i] <= pivot); 
                while(i < j && arr[--j] >= pivot); 
                if(i >= j)
                   break;
                swap(arr,i,j);               
            }
            arr[high - 1] = arr[i];
            arr[i] = pivot;
            sort(arr,low,i - 1);
            sort(arr,i + 1,high);
        }
    }
    public void swap(int[] arr,int i,int j){
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }
    public int getPivot(int[] arr,int low,int high){
        int mid = (low + high) / 2;
        if(arr[low] > arr[mid])
          swap(arr,low,mid);
        if(arr[low] > arr[high])
          swap(arr,low,high);
        if(arr[mid] > arr[high])
          swap(arr,mid,high);
        swap(arr,mid,high - 1);
        return arr[high - 1];
    }
}

运行结果:
在这里插入图片描述

2、利用归并排序
但是对于链表来说,利用归并排序,首先我们需要获取中间的节点。怎么实现这一步呢?利用快慢指针就好了,快指针走的是慢指针的2被,此时当快指针走完整个链表的时候,那么慢指针就是终点的位置了。然后进入递归,当链表为空或者只有一个节点的时候,那么就结束递归,进行合并的操作了。

对应的代码:

class Solution {
    /*
    利用归并排序对链表进行排序
    */
    public ListNode sortList(ListNode head) {
       return mergeSort(head);
    }
    public ListNode mergeSort(ListNode head){
        if(head != null && head.next != null){
        //如果链表不为空,并且不止一个节点的时候,那么就对这个链表进行分割
            ListNode cur,pre,tmp;
            pre = head;
            cur = head;
              //通过双指针,从而得到链表的中点
            while(cur != null && cur.next != null && cur.next.next != null){
            //循环条件必须是这样,因为需要考虑链表的节点的个数是奇数和偶数的情况
                pre = pre.next;
                cur = cur.next.next;
            }
            tmp = pre.next;
            pre.next = null; //基于上面while循环的判断条件,这一步是必要的,从而将链表彻底变成两条子链表
            ListNode left = mergeSort(head);
            ListNode right = mergeSort(tmp);
            ListNode sorted = merge(left,right);//对两条子链表进行排序,将排好序的
            return sorted; //返回排好序的链表的头结点
            
        }else{
        //如果链表为空,或者链表只有一个节点的时候,直接将这个节点返回
            return head;
        }
        
    }
    /*
    对两条有序链表进行合并的时候,合并时是在其中一条链表上操作的,而不是重
    新创建一条链表
    */
    public ListNode merge(ListNode head1,ListNode head2){
        ListNode cur1,cur2,pre,tmp;
        ListNode root = new ListNode(0);
        root.next = head1;
        pre = root;
        cur1 = head1;
        cur2 = head2;
        while(cur1 != null && cur2 != null){
            if(cur1.val < cur2.val){
                cur1 = cur1.next;
            }else{
                tmp = cur2.next;
                cur2.next = pre.next;
                pre.next = cur2;
                cur2 = tmp;
            } 
           /*
           这一步是关键,不可以将这一步写在if判断里面,否则就会导致错误
           比如当前的值是cur2的值小,如果将pre = pre.next这一步写在if判断
           里面,那么最后导致合并的链表缺少某些值
           */
            pre = pre.next; 
        }
        if(cur2 != null)
          pre.next = cur2;
        return root.next;
    }
}

运行结果:
在这里插入图片描述

但是考虑到ListNode是一个引用类型,那么在方法中对形参修改,会影响到实际的参数,所以原来的代码是这样的,但是结果是错误的,如果有大佬明白错误的原因的话,请指正。

 public ListNode sortList(ListNode head) {
       mergeSort(head);
       return head;
    }
    public void mergeSort(ListNode head){
        if(head != null && head.next != null){
            //通过双指针,从而得到链表的中点
            ListNode cur,pre,tmp;
            pre = head;
            cur = head;
            while(cur != null && cur.next != null && cur.next.next != null){
                pre = pre.next;
                cur = cur.next.next;
            }
            tmp = pre.next;
            pre.next = null;
            mergeSort(head);
            mergeSort(tmp);
            ListNode sorted = merge(head,tmp);
        }
        
    }
    public void merge(ListNode head1,ListNode head2){
        ListNode cur1,cur2,pre,tmp;
        ListNode root = new ListNode(0);
        root.next = head1;
        pre = root; 
        cur1 = head1;
        cur2 = head2;
        while(cur1 != null && cur2 != null){
            if(cur1.val < cur2.val){
                cur1 = cur1.next;
            }else{
                tmp = cur2.next;
                cur2.next = pre.next;
                pre.next = cur2;
                cur2 = tmp;
            } 
            pre = pre.next;
        }
        if(cur2 != null)
          pre.next = cur2;
        head1 =  root.next;
    }
  数据结构与算法 最新文章
【力扣106】 从中序与后续遍历序列构造二叉
leetcode 322 零钱兑换
哈希的应用:海量数据处理
动态规划|最短Hamilton路径
华为机试_HJ41 称砝码【中等】【menset】【
【C与数据结构】——寒假提高每日练习Day1
基础算法——堆排序
2023王道数据结构线性表--单链表课后习题部
LeetCode 之 反转链表的一部分
【题解】lintcode必刷50题<有效的括号序列
上一篇文章      下一篇文章      查看所有文章
加:2021-07-13 17:44:00  更:2021-07-13 17:47:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 17:27:18-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码