单链表的归并排序
时间复杂度O(nlog2 n),空间复杂度为O(1)
算法思想:
- 分,把链表不断划分成两个子链表,直到子链表中只含有一个元素,认为其是 有序的
- 治,它将两个有序数组合并成一个更大的有序数组
快慢指针:常用于判断链表中是否有环,简单来说就是有两个指针,快指针每次走两个节点慢指针每次走一个节点,当快指针走到链表尽头时,慢指针才走到了链表的一半,此时就是我们想要的中间节点
//链表结构体
typedef int ElemType ;
struct Node{
ElemType data;
Node* next;
} LNode, *LinkList;
Node* MergeSort(LinkList head){
//先判断链表长度是否大于1,小于1时无须排序
if(head!=NULL&&head->next!=NULL){
//运用快慢指针,找到链表的中间节点
Node *fast=head->next;
Node *slow=head;
while(fast!=NULL&&fast->next!=NULL){
fast=fast->next->next;
slow=slow->next;
}// 结束后slow指向mid,偶数时,指向的是中间元素的前一个
//将链表分成两部分进行分割
LNode *p1=MergeSort(slow->next);
slow->next=NULL; //断链分割
LNode *p2=MergeSort(head);
//对两条子链进行归并
// p0是排序后链表的头指针
LNode *p0=(Node *)malloc(sizeof(Node));
LNode *p=p0;
// 比较子链头部(对应子链的最小元素),较小链表头部链接到排好序的
// 链表的尾部,较小链表头部后移
while(p1!=NULL&&p2!=NULL){
if(p1->data < p2->data){
p->next=p1;
p1=p1->next;
}else{
p->next=p2;
p2=p2->next;
}
p=p->next;// p始终保持为排好序链表的尾指针
}
// 只剩p1或p2时,直接链接到排好序链表的后面
if(p1!=NULL){
p->next=p1;
}
if(p2!=NULL){
p->next=p2;
}
// 释放头指针返回链表
p=p0->next;
free(p0);
return p;
}
return head;// 空链表无需排序
}