大家可能对一维数组的快速排序和归并排序比较熟悉,单链表的快速排序和归并排序本质上与一维数组相同,但存在细微差别。
先介绍一下单链表的快速排序。快速排序的基本函数是partition函数,其功能是以一个参考节点的内容为参考值,将原数组的元素进行移位,移位结果
使得参考值节点左侧的节点值均小于等于该参考值,参考值节点右侧的节点值均大于大于该参考值。很多人比较熟悉的paitition算法是使用两个指针分别指向
数组的头、尾节点,然后使这两个节点不断往中间靠拢的算法。但是这种算法对单链表并不适用,因为无法通过单链表的尾节点直接找到尾节点的前一个节点。
于是,好多人可能觉得单链表无法用快速排序算法排序。其实不然。还有一种相同复杂度的partition算法,算法中参考指针只朝链表的方向移动,使用该partition
算法即可实现单链表的快速排序。
该partition算法的基本思路为:
1、将链表的第一个节点的值作为参考值,设置两个指针p0和p1。p0初始指向链表的第一个节点,p1初始指向链表的第二个节点。
从链表的首节点到p0节点,这些节点的值都小于等于参考值;p1表示最新遍历的节点。
2、p1不断先前推进,每当p1所指节点的值小于参考值,说明新找到一个值小于参考值的节点,将p0向前推进,然后该节点的值与p0的值交换。从而使得
已经处在正确位置的值小于等于参考值的节点数增加。由于p1每次找到一个值小于参考值的节点,都会将该节点的值与当前状态下最前面的一个值大于参考值
的节点值进行交换。因此,当p1推进到链表的末尾时,就可以保证链表的首节点到p0节点的节点值均小于等于参考值;p0-next到链表末尾的节点值均大于等于
参考值。
3、由于p0的节点值有可能小于参考值。因此,需要将p0的值与链表的首节点的值进行交换。
代码如下:
#include<iostream>
using namespace std;
struct Node
{
Node *next;
int data;
};
void qsort(Node *head, int n);
int main()
{
int n;
cin>>n;
Node *phead=NULL, *pNode=NULL;
int x;
if(n!=0)
{
phead=new Node();
cin>>phead->data;
phead->next=NULL;
//phead->data=x;
}
pNode=phead;
Node *temp=NULL;
for(int i=1; i<n; i++)
{
temp=new Node();
cin>>temp->data;
temp->next=NULL;
pNode->next=temp;
pNode=temp;
}
qsort(phead, n);
pNode=phead;
while(pNode!=NULL)
{
cout<<pNode->data<<" ";
pNode=pNode->next;
}
cout<<endl;
system("pause");
}
void qsort(Node *head, int n)
{
if(n==0 || n==1)
return;
Node *front=head;
Node *rear=front->next;
int ref;
ref=front->data;
int count=1;
int frontNum=0;
while(count<n)
{
if(rear->data<ref)
{
front=front->next;
++frontNum;
if(front!=rear)
{
int temp=rear->data;
rear->data=front->data;
front->data=temp;
}
}
rear=rear->next;
++count;
}
int temp=front->data;
front->data=head->data;
head->data=temp;
qsort(head, frontNum);
qsort(front->next, n-frontNum-1);
}
下面再介绍一下单链表的归并排序方法。
归并排序的基本思想是分治。将长度为n的数组等分成前后两端数组。先分别对钱后两端数组进行归并排序,然后将前后两端已经
排好序的子数组进行合并。 一维数组可以直接跳过下标以O(1)的复杂度找到前后两端数组的分界线,而链表只能通过逐个节点遍历的方法找到前后
两端数组的分界线。想要找到单链表的中间节点,可以使用两个指针。一个指针p1以2步长向前推进,另一个指针p0以一步长向前推进。当p1移动到
链表末尾时,p0即链表的中间节点。
实现代码如下:
#include<iostream>
using namespace std;
struct Node
{
Node *next;
int data;
};
Node* mergesort(Node *head, Node *rear);
int main()
{
int n;
cin>>n;
Node *phead=NULL, *pNode=NULL;
int x;
if(n!=0)
{
phead=new Node();
cin>>phead->data;
phead->next=NULL;
//phead->data=x;
}
pNode=phead;
Node *temp=NULL;
for(int i=1; i<n; i++)
{
temp=new Node();
cin>>temp->data;
temp->next=NULL;
pNode->next=temp;
pNode=temp;
}
phead=mergesort(phead, pNode);
pNode=phead;
while(pNode!=NULL)
{
cout<<pNode->data<<" ";
pNode=pNode->next;
}
cout<<endl;
system("pause");
}
Node* mergesort(Node *head, Node *rear)
{
if(head==NULL)
return NULL;
rear->next=NULL;
if(head==rear)
return head;
Node *p0=head, *p1=head;
while(p1->next!=NULL)
{
p1=p1->next;
if(p1->next!=NULL)
{
p0=p0->next;
p1=p1->next;
}
}
Node *head1=p0->next;
Node* pfront=mergesort(head, p0);
Node* pbehind=mergesort(head1, rear);
Node *resHead=NULL;
if(pfront->data < pbehind->data)
{
resHead=pfront;
pfront=pfront->next;
}
else
{
resHead=pbehind;
pbehind=pbehind->next;
}
Node *ptemp=resHead;
while(pfront!=NULL && pbehind!=NULL)
{
if(pfront->data < pbehind->data)
{
ptemp->next=pfront;
ptemp=ptemp->next;
pfront=pfront->next;
}
else
{
ptemp->next=pbehind;
ptemp=ptemp->next;
pbehind=pbehind->next;
}
}
if(pfront!=NULL)
ptemp->next=pfront;
else
ptemp->next=pbehind;
return resHead;
}