单链表的快速排序和归并排序

大家可能对一维数组的快速排序和归并排序比较熟悉,单链表的快速排序和归并排序本质上与一维数组相同,但存在细微差别。

        先介绍一下单链表的快速排序。快速排序的基本函数是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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值