严蔚敏《数据结构》 快速排序&堆排序

快速排序 

        快速排序是对冒泡排序进行改进的一种交换排序,可以大大加快排序的速度。

        快速排序具体的算法思想是在待排序的序列中任选一个数作为枢轴值(pivotkey),用双指针一个指向表的第一个值(low=1),另一个指向最后一个值(high=L.length)。若high指针指向的值大于枢轴值,则high指针向前移动,否则将high与枢轴记录交换。再从low指针的位置找到比枢轴值大的记录放到high的位置。当low=high时将初始选中的枢轴值放在那个位置。这样,在枢轴值两侧分为了两个都大于它或都小于它的两个子表,并按以上步骤不断递归最后得到正确的排序序列。

        算法如下

int Partition(SqList &L,int low,int high)    //对子表进行排序,返回枢轴位置 
{
	L.r[0]=L.r[low]; 
	int pivotkey=L.r[low];    //将关键字记录在pivotkey中 
	while(low<high)
	{
		while(low<high&&L.r[high]>=pivotkey)
		{
			--high;
		}
		L.r[low]=L.r[high];
		while(low<high&&L.r[low]<=pivotkey)
		{
			++low;
		}
		L.r[high]=L.r[low];
	} 
	L.r[low]=L.r[0];
	return low;
}
void QSort(SqList &L,int low,int high)
{
    if(low<high)
    {
    	int pivotloc=Partition(L,low,high);
    	QSort(L,low,pivotloc-1);   //左子表递归 
    	QSort(L,pivotloc+1,high);  //右子表递归 
	}
}
void QuickSort(SqList &L)
{
	QSort(L,1,L.length);
	cout<<"快速排序为: ";
	for(int i=1;i<=L.length;i++)
	{
		cout<<L.r[i]<<" ";
	}
 }

 堆排序

        堆排序是一种树形选择排序,借助完全二叉树的关系利用大根堆或小根堆实现排序的算法。

堆排序的实现分为建初堆和调整堆两个步骤。

        调整堆是对完全二叉树中的某一节点,选出它左右孩子中较大孩子的标号并将它与选中节点进行比较。若该节点小于其左右孩子中较大的节点,则将其位置进行交换。

        建初堆是从最后一个分支节点(n/2)开始,将这个节点到1的所有节点都调整为堆。

        采用以上方法可将待排序的完全二叉树调整为大根堆,堆排序则是将头结点与最后一个节点交换,并重新调整为大根堆,以此不断递归,最后输出升序的序列。

        算法如下:

void HeapAdjust(SqList &L,int s,int m)
 {
 	int rc=L.r[s];
 	for(int j=2*s;j<=m;j*=2)
 	{
 		if(j<m&&L.r[j]<L.r[j+1])    //取较大的左右孩子的标号 
 		{
 			++j;
		}
		 else if(rc>L.r[j])     //将根s与较大的左右孩子比较 
		 {
		 	break;
		 }		
		L.r[s]=L.r[j];
		L.r[j]=rc;
		s=j;
	 }
 }
 void CreateHeap(SqList &L)
 {
 	int n=L.length;
 	for(int i=n/2;i>0;i-=1)
 	{
 		HeapAdjust(L,i,n);
	}
 }
 void HeapSort(SqList &L)
 {
 	CreateHeap(L);
 	int i;
 	for(i=L.length;i>1;i-=1)
 	{
 		int x=L.r[1];
 		L.r[1]=L.r[i];
 		L.r[i]=x; 
		HeapAdjust(L,1,i-1);		//重新调整为大根堆 
    }
    cout<<"堆排序为: ";
	for(i=1;i<=L.length;i++)
	{
		cout<<L.r[i]<<" ";
	}
 }

        快速排序和堆排序都是不稳定的排序算法。

时间复杂度:

        快速排序最好情况为O(nlog2n),最坏情况为O(n方),平均情况为O(nlog2n)

        堆排序最好最坏平均情况都是O(nlog2n)

空间复杂度:

        快速排序为O(log2n),堆排序为O(1)

完整代码如下:

#include<iostream>
#include<algorithm>
using namespace std;
#define MAXSIZE 20
struct SqList
{
	int r[MAXSIZE+1];
	int length;
};
int Partition(SqList &L,int low,int high)    //对子表进行排序,返回枢轴位置 
{
	L.r[0]=L.r[low]; 
	int pivotkey=L.r[low];    //将关键字记录在pivotkey中 
	while(low<high)
	{
		while(low<high&&L.r[high]>=pivotkey)
		{
			--high;
		}
		L.r[low]=L.r[high];
		while(low<high&&L.r[low]<=pivotkey)
		{
			++low;
		}
		L.r[high]=L.r[low];
	} 
	L.r[low]=L.r[0];
	return low;
}
void QSort(SqList &L,int low,int high)
{
    if(low<high)
    {
    	int pivotloc=Partition(L,low,high);
    	QSort(L,low,pivotloc-1);   //左子表递归 
    	QSort(L,pivotloc+1,high);  //右子表递归 
	}
}
void QuickSort(SqList &L)
{
	QSort(L,1,L.length);
	cout<<"快速排序为: ";
	for(int i=1;i<=L.length;i++)
	{
		cout<<L.r[i]<<" ";
	}
 }
 
 //堆排序 
 void HeapAdjust(SqList &L,int s,int m)
 {
 	int rc=L.r[s];
 	for(int j=2*s;j<=m;j*=2)
 	{
 		if(j<m&&L.r[j]<L.r[j+1])    //取较大的左右孩子的标号 
 		{
 			++j;
		}
		 else if(rc>L.r[j])     //将根s与较大的左右孩子比较 
		 {
		 	break;
		 }		
		L.r[s]=L.r[j];
		L.r[j]=rc;
		s=j;
	 }
 }
 void CreateHeap(SqList &L)
 {
 	int n=L.length;
 	for(int i=n/2;i>0;i-=1)
 	{
 		HeapAdjust(L,i,n);
	}
 }
 void HeapSort(SqList &L)
 {
 	CreateHeap(L);
 	int i;
 	for(i=L.length;i>1;i-=1)
 	{
 		int x=L.r[1];
 		L.r[1]=L.r[i];
 		L.r[i]=x; 
		HeapAdjust(L,1,i-1);		//重新调整为大根堆 
    }
    cout<<"堆排序为: ";
	for(i=1;i<=L.length;i++)
	{
		cout<<L.r[i]<<" ";
	}
 }
 
int main()
{
	SqList L;
	//SqList L.r[MAXSIZE];
	cout<<"输入数组长度:"<<endl;
	cin>>L.length;
	cout<<"输入数据:"<<endl;
	for(int i=1;i<=L.length;i++)
	{
		cin>>L.r[i];
	}
	QuickSort(L);
	cout<<endl;
	HeapSort(L); 
}
 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值