思路:
1.将链表的中点找到,对其切分成2条
2.继续步骤1,切成4条,8条。。。,直至每段链表只有1个元素
3.归并操作,对两两链表进行合并排序,并返回回并后的链表的头结点,依次向上递归回去
C++代码实现
链表头文件链接:https://github.com/hitskyer/course/tree/master/dataAlgorithm/chenmingming/linkedList/homework
//归并排序
// Created by mingm on 2019/3/23.
//
#include <iostream>
#include <time.h>
#include <cstdlib>
#include "./homework/singleList.cpp"
using namespace std;ListNode GetMidNode(ListNode s) //快慢指针法,获取中间节点
{ListNode fast, slow;fast = s->pNext;//让快指针早点到达末位,慢指针指向中点或者(偶数个长度时)中点前一个位置slow = s;while(fast && fast->pNext){fast = fast->pNext->pNext;slow = slow->pNext;}return slow;
}
ListNode mergeList(ListNode L, ListNode R) //归并函数
{if(L == NULL) //如果一边为空,则返回另一边的头结点return R;if(R == NULL)return L;ListNode tempL = L, tempR = R; //把左右表头存储起来ListNode temp = new SNode, emptyHead = temp; //利用一个空表头哨兵tempwhile(tempL && tempR) //左右链表均不为空的话,进行数据比较{if(tempL->data < tempR->data){temp->pNext = tempL;temp = temp->pNext;tempL = tempL->pNext;}else{temp->pNext = tempR;temp = temp->pNext;tempR = tempR->pNext;}}if(tempL) //如果左边还有剩余的节点,把其接入链表末尾temp->pNext = tempL;if(tempR) //如果右边还有剩余的节点,把其接入链表末尾temp->pNext = tempR;temp = emptyHead->pNext; //实际链表数据节点表头delete emptyHead; //释放new出来的哨兵emptyHead = NULL;return temp; //返回链表数据头结点
}
ListNode divList(ListNode Lhead)
{if(Lhead == NULL || Lhead->pNext == NULL) //链表长度为0或者1,不用排序return Lhead;ListNode Mid = GetMidNode(Lhead); //获取链表中间节点(如果长度为2,则Mid是第一个节点)ListNode Rhead = Mid->pNext; //右边链表表头地址Mid->pNext = NULL; //断开左右链表ListNode L = divList(Lhead); //继续对左右两条链表进行划分ListNode R = divList(Rhead);return mergeList(L,R); //返回merge后的链表的表头
}
ListNode mergeSort(ListNode head) //归并排序入口,将头结点地址传入
{if(head == NULL || head->pNext == NULL) //链表长度为0或者1,不用排序return head;elsedivList(head); //长度大于1,则对其进行划分将链表切片
}int main()
{srand((unsigned)time(NULL)); //用时间随机数种子size_t len = 10; //测试链表最大长度for(size_t j = 0; j < len; ++j){SingleList intList;for(size_t i = 0; i < j; ++i){intList.AddTail(rand()%100); //添加随机数到链表}cout << "before merge sort: " << endl;intList.PrintList(); //排序前链表打印intList.SetHeadNode(mergeSort(intList.GetHeadNode())); //把排序后的链表的头结点设置成链表的头结点cout << "after merge sort: " << endl;intList.PrintList(); //排序后链表打印}return 0;
}