/*
归并排序
(算法交换链表节点,时间复杂度O(nlogn),不考虑递归栈空间的话空间复杂度是O(1))
首先用快慢指针的方法找到链表中间节点,然后递归的对两个子链表排序,
把两个排好序的子链表合并成一条有序的链表。归并排序应该算是链表排序最佳的选择了,
保证了最好和最坏时间复杂度都是nlogn,
而且它在数组排序中广受诟病的空间复杂度在链表排序中也从O(n)降到了O(1)
*/
node_t* get_mid(node_t* head)
{
node_t* fast = NULL;
node_t* slow = NULL;
if (NULL == head || head->next == NULL)
return head;
//使用 slow-fast方法找到链表的中间位置,注意这里写的链表的头节点是非空的,即头节点也是存贮数据的
fast = head->next; // fast指向第2个节点
slow = head; // slow指向第1个节点
while (fast != NULL&&fast->next != NULL)
{
fast = fast->next->next; //fast每次走两步
slow = slow->next; //slow每次走一步,这样slow就会到链表中点
}
//slow最后指向有n个元素的链表的第n/2个元素。
//如一共6个元素,slow指向第3个,一共5个元素,slow指向第2个。
return slow;
}
node_t* merge(node_t* newLeft, node_t* newRight)
{
node_t * newList = NULL;
node_t * tail = NULL;
if (NULL == newLeft || NULL == newRight)
return NULL;
//注意指针tail才是后面进行操作的指针,newList是为了保存起点
//printf ("i = %d\n", i++);//一直为0,说明递归时变量生存期只在函数内部
if (newLeft->data < newRight->data)
{
newList = newLeft;
newLeft = newLeft->next;
}
else
{
newList = newRight;
newRight = newRight->next;
}
tail=newList;
tail->next = NULL;
//以上代码是向newList的第一个节点存入左右两个链表的头节点的较小的元素
while (newLeft != NULL|| newRight != NULL)
{
if (newLeft == NULL) //左边全部接完了
{
tail->next = newRight; //右边就直接整条链表接上去
newRight = NULL;
}
else if (newRight == NULL)
{ //同理,右边接完了
tail->next = newLeft; //左边就直接整条链表接上去,复杂度为O(1)
newLeft = NULL;
}
else if (newLeft->data < newRight->data)
{
tail->next = newLeft; //上面接一整个链表,这里就是接链表中单个元素的操作
newLeft = newLeft->next;
tail = tail->next;
tail->next = NULL;
}
else
{
tail->next = newRight;
newRight = newRight->next;
tail = tail->next;
tail->next = NULL;
}
}
return newList; //返回新接好的List
}
node_t* listMergeSort(node_t* head) //传入需要归并排序的链表的头指针
{
node_t* left = NULL;
node_t* right = NULL;
node_t* mid = NULL;
node_t* newLeft = NULL;
node_t* newRight = NULL;
//一个元素就返回
if (NULL == head || head->next == NULL)
return head;
mid = get_mid(head);//mid最后指向有n个元素的链表的第n/2个元素。
left = head;
right = mid->next;
mid->next = NULL;
//但是实际上将链表截断,左边的部分从第1个开始,右边的要从第4个(共6个)或者第3个(共5个)开始,所以有right=slow->next;
//假设上面截断的左右两个子链表调用归并排序后变成了排好序(new,新)的“新”左右两个链表,然后开始归并
printf("left head = %d_%d, right head = %d_%d\n", left->index, left->data, right->index, right->data);
newLeft = listMergeSort(left);
newRight = listMergeSort(right);
printf("newLeft head = %d_%d, newRight head = %d_%d\n", newLeft->index, newLeft->data, newRight->index, newRight->data);
return merge(newLeft, newRight);
}
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
void merge(int a[],int l,int r,int mid)
{
int aux[r-l+1],i,j,k;
for(k=l;k<=r;k++)
aux[k-l]=a[k];
i=l;
j=mid+1;
for(k=l;k<=r;k++)
{
if(i>mid)
{
a[k]=aux[j-l];
j++;
}
else if(j>r)
{
a[k]=aux[i-l];
i++;
}
else if(aux[i-l]>aux[j-l])
{
a[k]=aux[j-l];
j++;
}
else
{
a[k]=aux[i-l];
i++;
}
}
}
void merge_sort(int a[],int l,int r)
{
if(l>=r)
return ;
int mid=(l+r)/2;
merge_sort(a,l,mid);
merge_sort(a,mid+1,r);
merge(a,l,r,mid);
}
void mergesort(int a[],int l,int r)
{
merge_sort(a,l,r-1);
}
https://www.cnblogs.com/TenosDoIt/p/3666585.html