上篇博客中讲解了九大内部排序算法,部分算法还提供了代码实现,但是那些代码实现都是基于数组进行排序的,本篇博客就以链表排序实现几种常见的排序算法,以飨读者。
快速排序的链表实现
算法思想:对于一个链表,以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 }
先写这几种吧,想起来再更。。。