• 常见的链表排序(Java版)


           上篇博客中讲解了九大内部排序算法,部分算法还提供了代码实现,但是那些代码实现都是基于数组进行排序的,本篇博客就以链表排序实现几种常见的排序算法,以飨读者。

    快速排序的链表实现

    算法思想:对于一个链表,以head节点的值作为key,然后遍历之后的节点,可以得到一个小于key的链表和大于等于key的链表;由此递归可以对两个链表分别进行快速。这里用到了快速排序的思想即经过一趟排序能够将小于key的元素放在一边,将大于等于key的元素放在另一边。

    代码实现:

     1     //快速排序
     2     public static void quickSort(ListNode begin, ListNode end){
     3         if(begin == null || begin == end)
     4             return;
     5         
     6         ListNode index = paration(begin, end);
     7         quickSort(begin, index);
     8         quickSort(index.next, end);
     9     }
    10     
    11     /**
    12      * 划分函数,以头结点值为基准元素进行划分
    13      * @param begin
    14      * @param end
    15      * @return
    16      */
    17     public static ListNode paration(ListNode begin, ListNode end){
    18         if(begin == null || begin == end)
    19             return begin;
    20         
    21         int val = begin.val;  //基准元素
    22         ListNode index = begin, cur = begin.next;
    23         
    24         while(cur != end){
    25             if(cur.val < val){  //交换
    26                 index = index.next;
    27                 int tmp = cur.val;
    28                 cur.val = index.val;
    29                 index.val = tmp;
    30             }
    31             cur = cur.next;
    32         }
    33         
    34         
    35         begin.val = index.val;
    36         index.val = val;
    37         
    38         return index;
    39     }

    归并排序的链表实现

    算法思想:单链表与数组相比只能顺序访问每个元素,因此在使用二路归并排序时关键在于找到链表的中间结点将链表一分为二:可以利用快慢指针同时遍历单链表,当步长为2的指针指向链表最后一个结点或者最后一个结点的下一个结点时,步长为1的指针即指向链表的中间结点。然后是两个有序单链表的合并问题。时间复杂度为O(N*logN),空间复杂度为O(1)。

    代码实现:

     1     //归并排序
     2     public static ListNode mergeSort(ListNode head){
     3         if(head == null || head.next == null)  //空链表或者只有单个结点
     4             return head;
     5         ListNode slow = head, fast = head.next;
     6         
     7         while(fast != null && fast.next != null){  //使用快慢指针寻找中间 结点
     8             slow = slow.next;
     9             
    10             fast = fast.next;
    11             if(fast.next != null)
    12                 fast = fast.next;        
    13         }
    14         
    15         ListNode ptr1 = slow.next;
    16         slow.next = null;
    17         
    18         ListNode tmp1 = mergeSort(head);
    19         ListNode tmp2 = mergeSort(ptr1);
    20         return merge(tmp1, tmp2);
    21     }
    22     
    23     
    24     public static ListNode merge(ListNode start1,  ListNode start2){
    25         ListNode header = new ListNode(-1);
    26         ListNode pre = header;
    27         
    28         ListNode ptr1 = start1, ptr2 = start2;
    29         while(ptr1 != null && ptr2 != null){
    30             if(ptr1.val <= ptr2.val){
    31                 pre.next = ptr1;
    32                 pre = ptr1;
    33                 ptr1 = ptr1.next;
    34             }else{
    35                 pre.next = ptr2;
    36                 pre = ptr2;
    37                 ptr2 = ptr2.next;
    38             }
    39         }
    40         while(ptr1 != null){
    41             pre.next = ptr1;
    42             pre = ptr1;
    43             ptr1 = ptr1.next;
    44         }
    45         
    46         while(ptr2 != null){
    47             pre.next = ptr2;
    48             pre = ptr2;
    49             ptr2 = ptr2.next;
    50         }
    51         
    52         
    53         return header.next;
    54         
    55     }

    冒泡排序的链表实现

    算法思想:依次比较相邻的结点,如果是逆序的就交换两个结点

    代码实现:

     1     //冒泡排序
     2     public static ListNode bubbleSort(ListNode head){
     3         if(head == null || head.next == null)  //链表为空或者仅有单个结点
     4             return head;
     5         
     6         ListNode cur = null, tail = null;
     7         
     8         cur = head;
     9         
    10         while(cur.next != tail){
    11             while(cur.next != tail){
    12                 if(cur.val > cur.next.val){
    13                     int tmp = cur.val;
    14                     cur.val = cur.next.val;
    15                     cur.next.val = tmp;
    16                 }
    17                 cur = cur.next;
    18             }
    19             
    20             tail = cur;  //下一次遍历的尾结点是当前结点(仔细琢磨一下里面的道道)
    21             cur = head;     //遍历起始结点重置为头结点    
    22         }
    23         
    24         return head;
    25         
    26         
    27     }

    先写这几种吧,想起来再更。。。

     

  • 相关阅读:
    拼音输入法的数学原理
    搜索核心原理之网页和查询的相关性——TF-IDF
    Linux内核源码分析之调度、内核线程模型 And Centos7.2's Kernel Resource Analysis
    手把手教您定制化Centos6.x安装界面
    定制Centos系统(基于6.x)
    数据分析、数据挖掘之聚类、分类
    数据分析、数据挖掘之文档过滤、垃圾邮件
    数据分析、数据挖掘之特征分解、特征分析
    数据挖掘、数据分析之协同过滤、推荐系统、关联分析
    转载-“一代宗师”周金涛先生20个预言待验证
  • 原文地址:https://www.cnblogs.com/bywallance/p/6726251.html
Copyright © 2020-2023  润新知