//鏈表結構
class ListNode {
int val;
ListNode next;
ListNode(int x) {
val = x;
next = null;
}
單鏈表的插入排序
//鏈表的插入排序
public ListNode insertionSortList(ListNode head) {
//非空判斷 頭結點爲空或者
if(head==null||head.next==null)
{
return head;
}
//建立一個僞頭結點 便於頭結點的替換
ListNode unrealHead=new ListNode(Integer.MIN_VALUE);
unrealHead.next=head;//連接到頭結點上
ListNode curSortedIndex=head;//當前有序位置
ListNode nextSortIndex=head.next;//下一個需要進行排序的位置
//鏈表的排序不同於數組的排序 可以直接從頭部開始查找 不需要向數組那樣從有序位置向前查找 以簡化操作
while(nextSortIndex!=null)//仍有待排序的元素
{
//大於已經排序好鏈表的最大值
if(nextSortIndex.val>=curSortedIndex.val)//不需要變動位置
{
curSortedIndex=nextSortIndex;
nextSortIndex=nextSortIndex.next;
}
else
{
//從頭開始查找
ListNode curNode=unrealHead;
while(curNode.next.val<=nextSortIndex.val)
{
curNode=curNode.next;
}
//curNode指向的下一個元素已經大於nextSortIndex
//將nextSortIndex連接在curNode之後
ListNode assistNode=nextSortIndex;//輔助節點 記錄要插入的元素
nextSortIndex=nextSortIndex.next;//下一排序位置後移
curSortedIndex.next=nextSortIndex;//將斷開的鏈搭上
//元素插入指定位置
assistNode.next=curNode.next;
curNode.next=assistNode;
}
}
//排序完成 返回真正的頭結點
return unrealHead.next;
}
單鏈表的歸併排序
/**************
* 歸併排序的實現 最終要的在於實現二路歸併的算法
* 分成兩個部分 對左半部分進行歸併排序 對右半部分進行歸併排序
* 左右部分進行二路歸併
**************/
public ListNode sortList(ListNode head) {
//鏈表長度判斷
if(head==null||head.next==null)
{
return head;
}
ListNode midNode=findMidNode(head);
ListNode rightFirst=midNode.next;
midNode.next=null;
ListNode leftHead=sortList(head);
ListNode rightHead=sortList(rightFirst);
return mergeList(leftHead,rightHead);
}
/******************
* 查找鏈表的中間位置 並返回
* 查找思路爲使用兩個引用 一個一次後移兩格(快指針),一個一次後移一格(慢指針)
* 當快指針走到結尾時,慢指針正好走到中間位置
*
*鏈表節點個數爲偶數2n時,fast走到空時 ,slow在n位置
*鏈表節點爲奇數2n+1時,fast.next爲空時,slow在n的位置
*將鏈表分爲兩半時,中間節點分到前半部分
**************/
private ListNode findMidNode(ListNode head)
{
//爲空或只有一個節點
if(head==null||head.next==null)
{
return head;
}
//定義快節點和慢節點
ListNode fastNode=head.next;
ListNode slowNode=head;
//直到快節點走到null或者快節點的下一個節點爲null
while(fastNode!=null&&fastNode.next!=null)
{
fastNode=fastNode.next.next;
slowNode=slowNode.next;
}
//返回中間位置節點
return slowNode;
}
/********************
* 鏈表的二路歸併
* 返回連接後的頭節點 類似多項式的合併
********************/
private ListNode mergeList(ListNode first,ListNode second)
{
//左邊爲空 直接返回
if(first==null)
{
return second;
}
if(second==null)
{
return first;
}
ListNode curFirst=first;
ListNode curSecond=second;
//找尋頭節點 使用first存儲 second節點用於
if(first.val<second.val)
{
curFirst=curFirst.next;//指針後移
}
else
{
first=second;
curSecond=curSecond.next;
}
second=first;//已成鏈的最後一個節點
//循環查找 將節點搭在鏈上
while(curFirst!=null&&curSecond!=null)
{
if(curFirst.val<curSecond.val)
{
second.next=curFirst;//將first連接在節點之後
curFirst=curFirst.next;//first指針後移 指向下一個
}
else
{
second.next=curSecond;
curSecond=curSecond.next;
}
second=second.next;//鏈尾新加入一個節點
}
//判斷哪條鏈遍歷完成
if(curFirst==null) second.next=curSecond;
else
{
second.next=curFirst;
}
//返回頭結點
return first;
}