设有n个待排序元素存放在一个不带表头结点的单链表中,每个链表结点只存放一个元素,头指针为 r,试设计一个算法,对其进行二路归并排序,要求不移动结点中的元素,只能改动各链表结点中的指针,排序后 r 仍指示结果链表的第一个结点。
解题思路:
1.不带头结点的尾插法:单独将第一个元素存入到结点中,再插在头指针后面,后面的结点正常插入。
2.归并排序:先划分,再归并
划分:使用递归,先用快慢指针找到链表中的中值,从中间咔叽。将链表中前半部分排序的结果同后半段的排序结果归并。
归并:so easy 自己看
#include<stdio.h>
#include<algorithm>
using namespace std;
typedef struct Node
{
int data;
Node *next;
}Node,*List;
List build(int a[])//将待排序元素存入单链表中,使用尾插法
{
List r; //头指针
Node *head=(Node *)malloc(sizeof(Node));
head->data=a[0];
head->next=NULL;
r=head;
List tail=head;
for(int i=1;i<5;i++)
{
Node *p=(Node *)malloc(sizeof(Node));
p->data=a[i];
//p->next=tail->next;
tail->next=p;
tail=p;
}
tail->next=NULL;
return r;
}
void print(List r)
{
Node *p=r;
while(p)
{
printf("%d ",p->data);
p=p->next;
}
printf("\n");
}
List merge(List h1,List h2)//归并
{
List hh=(List)malloc(sizeof(Node));//建立新的头结点
List p=hh;//遍历指针
while(h1!=NULL&&h2!=NULL)
{
if(h1->data < h2->data)
{
p->next=h1;
p=h1;
h1=h1->next;
}
else
{
p->next=h2;
p=h2;
h2=h2->next;
}
}
if(h1!=NULL)//h1元素没用完,直接接到表尾
{
p->next=h1;
}
else if(h2!=NULL)
{
p->next=h2;
}
return hh->next;
}
List sort(List r)//划分
{
if(r->next==NULL)//若只有一个元素则返回
{
return r;
}
List slow=r;
List fast=r->next;
while(fast!=NULL&&fast->next!=NULL)//快指针走到NULL时,slow正好在链表中间位置
{
slow=slow->next;
fast=fast->next->next;
}
List h1=sort(slow->next);//截取后半部分链表进行排序
slow->next=NULL;//断开链表 ,把后半段咔叽掉
return merge(sort(r),h1);//前半部分排序后和后半部分排序后链表进行归并
}
int main()
{
int a[5]={5,6,1,4,3};
List r=build(a);
print(r);
r=sort(r);
print(r);
}