zoukankan      html  css  js  c++  java
  • 算法——排序链表

    给定一个乱序的链表,要求将链表进行排序后然后返回头结点,要求时间复杂度为 O(nlogn)。
    leetcode

    1. 由于无法快速得到链表中某一节点得值,时间复杂度为 O(nlogn),所以,通过归并排序。
    2. 归并的核心思想是将数据分为两段有序的数据,再进行合并。
    3. 归并的程序设计上可以由递归和迭代两种方法,迭代稍微复杂一些,需要计算每次段的长度。递归就利用分治的思想,每次将数据分为两段。

    首先是迭代方法。

    /**
     * created by lippon
     */
    class Solution {
        public ListNode sortList(ListNode head) {
            int n = 0; 
            // 定义一个虚拟节点,因为头节点会改变,所以,通过虚拟节点来指向头节点
            // 最后返回虚拟节点的下一节点即为头节点
            ListNode dummy = new ListNode(0);
            dummy.next= head;
    
    		// 计算链表长度
            ListNode cur = head;
            while(cur != null) {
                cur = cur.next;
                n ++;
            }
    
    		// 计算每次归并的长度,由小变大
            for(int i = 1; i < n; i *= 2) {
            	// 将当前指针指向头
                cur = dummy;
                // 计算归并段的起始位置
                for(int j = 0; j + i < n; j += 2 * i){
                	// 定义前后两个节点的位置
                    int x = 0, y = 0;
                    // 定义前后两个节点
                    ListNode first = cur.next;
                    ListNode second = cur.next;
    				// 将后指针送到后半段
                    int temp = 0;
                    while(temp < i && second != null) {
                        temp ++;
                        second = second.next;
                    }
    				// 前后两个节点都没超出段的情况下,将当前指针不断指向小的节点
    				// 这里需要注意的是后节点可能会超出链表长度
                    while(x < i && y < i && second != null) {
                        if(first.val < second.val) {
                            cur.next = first;
                            first = first.next;
                            cur = cur.next;
                            x ++;
                        } else {
                            cur.next = second;
                            second = second.next;
                            cur = cur.next;
                            y ++;
                        }
                    }
    				
    				// 接上剩余的节点
                    while(x < i) {
                        cur.next = first;
                        first = first.next;
                        cur = cur.next;
                        x ++;
                    }
    
                    while(y < i && second != null) {
                        cur.next = second;
                        second = second.next;
                        cur = cur.next;
                        y ++;
                    }
    				// 将当前节点接到下一段
                    cur.next = second;
                }
            }
    
            return dummy.next;
        }
    }
    

    递归方法

    class Solution {
        public ListNode sortList(ListNode head) {
             if(head == null ||head.next == null){
                return head;
            }
    
    		// 截取中间节点
            ListNode fast=head,slow=head,pre=null;
            while(fast!=null && fast.next!=null){
                fast = fast.next.next;
                pre = slow;
                slow = slow.next;
            }
            // head --->pre--->slow--->fast
            pre.next = null;
            // 分治前半部分 head ---> pre
            ListNode l1 = sortList(head);
            // 分治后半部分 slow ---> fast
            ListNode l2 = sortList(slow);
            // 将两个有序链表 l1,l2 归并
            return merge(l1,l2);
        }
    
        public ListNode merge(ListNode l1,ListNode l2){
            ListNode head = null,p = null;
            while(l1!=null && l2 != null){
                ListNode node;
                if(l1.val<l2.val){
                    node=l1;
                    l1=l1.next;
                }else{
                    node = l2;
                    l2 = l2.next;
                }
                if(p == null){
                    head = node;
                }else{
                    p.next = node;
                }
                p=node;
            }
            if(l1 != null){
                p.next = l1;
            }
            if(l2 != null){
                p.next = l2;
            }
            return head;
        }
    }
    
  • 相关阅读:
    C#获取类以及类下的方法(用于Asp.Net MVC)
    ES6学习笔记
    在nuget上发布自己的程序集教程
    C#创建IIS站点及相应的应用程序池,支持IIS6.0+Windows Server 2003. 使用Builder设计模式
    ASP.Net Mvc实现自定义User Identity用户身份识别系统(2)
    ASP.Net Mvc实现自定义User Identity用户身份识别系统(1)
    C#实现.ini文件读写操作
    C#实现注册表 LocalMachine 目录下CURD工具类
    博客园打赏功能(未申请下js权限使用二维码打赏功能)
    WebServeice 动态代理类
  • 原文地址:https://www.cnblogs.com/lippon/p/14117715.html
Copyright © 2011-2022 走看看