排序:快速排序与选择排序

31 篇文章 1 订阅
4 篇文章 0 订阅

      在最近的学习中,对于排序算法进行了一定的学习,在这里对快速排序和选择排序的部分内容进行说明,其余内容在后期会进行补充,感谢大家提出宝贵意见。


宏定义如下:

<span style="font-size:18px;"><strong><strong><span style="font-size:18px;">#include <iostream>
using namespace std;

#define M 21

typedef int SqList[M];</span></strong></strong></span>

一.冒泡排序

<span style="font-size:18px;"><strong><strong><span style="font-size:18px;">void BubbleSort(SqList &L,int n)                  //冒泡排序
{
	for(int i = 0;i < n-1;++i)                      //外层循环记录循环次数
	{
		for(int j = 0;j < n-i-1;++j)              //内层循环记录每一次循环比较的次数
		{                                         //(j<n-i-1)比较一次后,其后值不参与再比较
			if(L[j] > L[j+1])                     //若前者大于后者,则交换位置
			{
				int tmp = L[j];
				L[j] = L[j+1];
				L[j+1] = tmp;
			}
		}
	}
}</span></strong></strong></span>

二.快速排序

<span style="font-size:18px;"><strong><strong><span style="font-size:18px;">//改进方式,直接赋值
int Partition(SqList &L,int low,int high)         //返回枢轴所在位置,它之前的小于它
{                                                 //之后的大于它
	int key = L[low];                             //枢轴记录关键字
	while(low < high)                             //判别条件,不满足时结束
	{
		while(low < high && L[high] >= key )      //若右边的大于枢轴
		{
			high--;                               //向前比较
		}
		L[low] = L[high];                         //否则赋值
		while(low < high && L[low] <= key)        //若左边的小于枢轴
		{
			low++;                                //向后比较
		}
		L[high] = L[low];                         //否则赋值
	}
	L[low] = key;                                 //此时low = high,即可等价为L[high] = key,枢轴记录到位
	return low;                                   //返回此时位置
}

//交换方式
/*int Partition(SqList &L,int low,int high)
{
	int key = L[low];
	while(low < high)
	{
		while(low < high && L[high] >= key )
		{
			high--;
		}
		int tmp = L[low];
		L[low] = L[high];
		L[high] = tmp;
		while(low < high && L[low] <= key)
		{
			low++;
		}
		tmp = L[low];
		L[low] = L[high];
		L[high] = tmp;
	}
	return low;
}*/

void QuickSort(SqList &L,int low,int high)        //快速排序
{
	if(low < high)
	{
		int prvitloc = Partition(L,low,high);     //将数组一分为二
		QuickSort(L,low,prvitloc-1);              //左半部分排序
		QuickSort(L,prvitloc+1,high);             //右半部分排序
	}
}</span></strong></strong></span>

对于快速排序有如下的优化方法:

1.L[low] L[high] L[(low+high)/2]从中找中间值作为枢值

实现代码如下:

//改进方法 L[low] L[high] L[(low+high)/2]从中找中间值作为枢值
int Index(int a,int b,int c)                                //查找作为枢值的值
{
	if(a < b)
	{
		if(a < c)
		{
			if(b < c)
			{
				return b;
			}
			else
			{
				return c;
			}
		}
		else
		{
			return a;
		}
	}
	else //b <= a
	{
		if(c < a)
		{
			if(b < c)
			{
				return b;
			}
			else
			{
				return c;
			}
		}
		else
		{
			return a;
		}
	}
}

int Partition(SqList &L,int low,int high)         //返回枢轴所在位置,它之前的小于它
{                                                 //之后的大于它
	int key = Index(L[low],L[high],L[(low+high)/2]);
	while(low < high)                             //判别条件,不满足时结束
	{
		while(low < high && L[high] >= key )      //若右边的大于枢轴
		{
			high--;                               //向前比较
		}
		int tmp = L[low];                         //交换位置
		L[low] = L[high];
		L[high] = tmp;                         
		while(low < high && L[low] < key)         //若左边的小于枢轴
		{
			low++;                                //向后比较
		}
		tmp = L[low];                             //交换位置
		L[low] = L[high];
		L[high] = tmp;                       
	} 
	return low;                                   //返回此时位置
}

测试代码与原方法相同。

2.改进方法 L[low] L[high] L[(low+high)/2]从中找中间值作为枢值且在指针high增1和low减1时同时进行冒泡操作,即在相邻两个纪录处于“逆序”时进行交换,同时算法中附设两个布尔型变量分别指示low和high在从两端向中间移动过程中是否进行交换记录的操作,若指针low在从低端向中间的移动过程中没有进行交换记录的操作,则不再需要对低端子表进行操作,同理高端子表类似。

实现代码如下:

//改进方法 L[low] L[high] L[(low+high)/2]从中找中间值作为枢值且在指针high增1和low减1时同时进行冒泡操作
//即在相邻两个纪录处于“逆序”时进行交换,同时算法中附设两个布尔型变量分别指示low和high在从两端向中间
//移动过程中是否进行交换记录的操作,若指针low在从低端向中间的移动过程中没有进行交换记录的操作,则不再
//需要对低端子表进行操作,同理高端子表类似

int Index(int a,int b,int c)                                //查找作为枢值的值
{
	if(a < b)
	{
		if(a < c)
		{
			if(b < c)
			{
				return b;
			}
			else
			{
				return c;
			}
		}
		else
		{
			return a;
		}
	}
	else //b <= a
	{
		if(c < a)
		{
			if(b < c)
			{
				return b;
			}
			else
			{
				return c;
			}
		}
		else
		{
			return a;
		}
	}
}

bool Right(SqList &L,int low,int high)             //布尔型变量指示low从左向中间移动过程中是否进行交换记录的操作
{
    int key = Index(L[low],L[high],L[(low+high)/2]);
	while(low < high && L[high] >= key )      //若右边的大于枢轴
	{
		int tmp = high;
		high--;                               //向前比较
		if(L[tmp] < L[high])
		{
			return true;                     //判断真值
		}
	}                     
	while(low < high && L[low] < key)         //若左边的小于枢轴
	{
		int tmp = low;
		low++;                                //向后比较
	}                       
}

bool Left(SqList &L,int low,int high)             //布尔型变量指示high从右向中间移动过程中是否进行交换记录的操作
{
	int key = Index(L[low],L[high],L[(low+high)/2]);
	while(low < high && L[high] >= key )      //若右边的大于枢轴
	{
		int tmp = high;
		high--;                               //向前比较
	}                        
	while(low < high && L[low] < key)         //若左边的小于枢轴
	{
		int tmp = low;
		low++;                                //向后比较
		if(L[tmp] > L[low])
		{
			return true;
		}
	}                   
}

int Partition(SqList &L,int low,int high)         //返回枢轴所在位置,它之前的小于它
{                                                 //之后的大于它
    int key = Index(L[low],L[high],L[(low+high)/2]);
	while(low < high)                             //判别条件,不满足时结束
	{
		while(low < high && L[high] >= key )      //若右边的大于枢轴
		{
			int tmp = high;
			high--;                               //向前比较
			if(L[tmp] < L[high])                  //相邻两位比较大小
			{
				int exp = L[tmp];
				L[tmp] = L[high];
				L[high] = exp;
			}
		}                        
		while(low < high && L[low] < key)         //若左边的小于枢轴
		{
			int tmp = low;
			low++;                                //向后比较
			if(L[tmp] > L[low])                   //相邻两位比较大小
			{
				int exp = L[tmp];
				L[tmp] = L[low];
				L[low] = exp;
			}
		}                     
	} 
	return low;                                   //返回此时位置
}

测试代码有了一定改变,如下所示:

void QuickSort(SqList &L,int low,int high)        //快速排序
{
	bool left = Left(L,low,high);
	bool right = Right(L,low,high) ;
	if(low < high)
	{
		int prvitloc = Partition(L,low,high);         //将数组一分为二
		if(!left)                                     //若左半部分没有进行数值交换
		{
			QuickSort(L,low,prvitloc-1);              //左半部分排序
		}
		if(!right)                                    //若右半部分没有进行数值交换
		{
			QuickSort(L,prvitloc+1,high);             //右半部分排序
		}
	}
}

三.简单选择排序

<span style="font-size:18px;"><strong><strong><span style="font-size:18px;">int SelectMinKey(SqList &L,int n,int key)         //选择第key小的记录下标     
{
	for(int k = key+1;k < n;++k)                  //只比较key之后的
	{
		if(L[k] < L[key])                         //若小于则记录下标
		{
			key = k;
		}
	}
	return key;                                   //返回下标
}

void SelectSort(SqList &L,int n)                  //简单选择排序
{
	for(int i = 0;i < n-1;++i)
	{
		int j = SelectMinKey(L,n,i);              //第key小的记录位置
		if(i != j)                                //若不为此位置数,则交换位置
		{
			int tmp = L[i];
			L[i] = L[j];
			L[j] = tmp;
		}
	}
}</span></strong></strong></span>

四.堆排序

void Heapify(SqList &L,int low,int high)
{
	int sq = L[low];                         //将根结点保存在sq中
	for(int j = 2*low;j <= high;j *= 2)      
	{
		if(j < high && L[j] < L[j+1])        //沿关键字较大的孩子结点向下筛选
		{
			j++;                             //关键字较大节点下标
		}
		if(sq > L[j])                        //若孩子结点的值小于根结点的值,则不进行交换
		{
			break;
		}
		L[low] = L[j];
		low = j;
	}
	L[low] = sq;                             //将根结点插入到正确位置
}


void BuildHeap(SqList &L,int n)         //建立大顶堆
{
	for(int i = n/2;i > 0;i--)          //从序号n/2开始建立大顶堆
	{
		Heapify(L,i,n);
	}
}


void HeapSort(SqList &L,int n)
{                                       //对L[1..n]进行堆排序,不妨用L[0]做暂存单元
	BuildHeap(L,n);                     //将L[1-n]建成初始堆
	for(int i = n-1;i > 1;i--){ 
		                                //对当前无序区L[1..i]进行堆排序,共做n-1趟。
		L[0]=L[1];
		L[1]=L[i];
		L[i]=L[0];
		                                //将堆顶和堆中最后一个记录交换
		Heapify(L,1,i-1);
		                                //将L[1..i-1]重新调整为堆,仅有L[1]可能违反堆性质
	} 
} 

测试代码如下:

void main()
{
	SqList sq = {0,53,24,35,56,32,78,99}; 
	HeapSort(sq,8);
	for(i = 1;i < 8; ++i)
	{
		cout<<sq[i]<<" ";
	}
	cout<<endl;
}


具体代码如上,如有任何问题请大家指出,谢谢。


如下附上完整版函数和测试代码:

#include <iostream>
using namespace std;

#define M 21

typedef int SqList[M];

void BubbleSort(SqList &L,int n)                  //冒泡排序
{
	for(int i = 0;i < n-1;++i)                    //外层循环记录循环次数
	{
		for(int j = 0;j < n-i-1;++j)              //内层循环记录每一次循环比较的次数
		{                                         //(j<n-i-1)比较一次后,其后值不参与再比较
			if(L[j] > L[j+1])                     //若前者大于后者,则交换位置
			{
				int tmp = L[j];
				L[j] = L[j+1];
				L[j+1] = tmp;
			}
		}
	}
}


//改进方法 L[low] L[high] L[(low+high)/2]从中找中间值作为枢值
int Index(int a,int b,int c)                                //查找作为枢值的值
{
	if(a < b)
	{
		if(a < c)
		{
			if(b < c)
			{
				return b;
			}
			else
			{
				return c;
			}
		}
		else
		{
			return a;
		}
	}
	else //b <= a
	{
		if(c < a)
		{
			if(b < c)
			{
				return b;
			}
			else
			{
				return c;
			}
		}
		else
		{
			return a;
		}
	}
}

/*int Partition(SqList &L,int low,int high)         //返回枢轴所在位置,它之前的小于它
{                                                 //之后的大于它
	int key = Index(L[low],L[high],L[(low+high)/2]);
	while(low < high)                             //判别条件,不满足时结束
	{
		while(low < high && L[high] >= key )      //若右边的大于枢轴
		{
			high--;                               //向前比较
		}
		int tmp = L[low];                         //交换位置
		L[low] = L[high];
		L[high] = tmp;                         
		while(low < high && L[low] < key)         //若左边的小于枢轴
		{
			low++;                                //向后比较
		}
		tmp = L[low];                             //交换位置
		L[low] = L[high];
		L[high] = tmp;                       
	} 
	return low;                                   //返回此时位置
}*/


//改进方法 L[low] L[high] L[(low+high)/2]从中找中间值作为枢值且在指针high增1和low减1时同时进行冒泡操作
//即在相邻两个纪录处于“逆序”时进行交换,同时算法中附设两个布尔型变量分别指示low和high在从两端向中间
//移动过程中是否进行交换记录的操作,若指针low在从低端向中间的移动过程中没有进行交换记录的操作,则不再
//需要对低端子表进行操作,同理高端子表类似


bool Right(SqList &L,int low,int high)             //布尔型变量指示low从左向中间移动过程中是否进行交换记录的操作
{
    int key = Index(L[low],L[high],L[(low+high)/2]);
	while(low < high && L[high] >= key )      //若右边的大于枢轴
	{
		int tmp = high;
		high--;                               //向前比较
		if(L[tmp] < L[high])
		{
			return true;                     //判断真值
		}
	}                     
	while(low < high && L[low] < key)         //若左边的小于枢轴
	{
		int tmp = low;
		low++;                                //向后比较
	}                       
}

bool Left(SqList &L,int low,int high)             //布尔型变量指示high从右向中间移动过程中是否进行交换记录的操作
{
	int key = Index(L[low],L[high],L[(low+high)/2]);
	while(low < high && L[high] >= key )      //若右边的大于枢轴
	{
		int tmp = high;
		high--;                               //向前比较
	}                        
	while(low < high && L[low] < key)         //若左边的小于枢轴
	{
		int tmp = low;
		low++;                                //向后比较
		if(L[tmp] > L[low])
		{
			return true;
		}
	}                   
}

int Partition(SqList &L,int low,int high)         //返回枢轴所在位置,它之前的小于它
{                                                 //之后的大于它
    int key = Index(L[low],L[high],L[(low+high)/2]);
	while(low < high)                             //判别条件,不满足时结束
	{
		while(low < high && L[high] >= key )      //若右边的大于枢轴
		{
			int tmp = high;
			high--;                               //向前比较
			if(L[tmp] < L[high])                  //相邻两位比较大小
			{
				int exp = L[tmp];
				L[tmp] = L[high];
				L[high] = exp;
			}
		}                        
		while(low < high && L[low] < key)         //若左边的小于枢轴
		{
			int tmp = low;
			low++;                                //向后比较
			if(L[tmp] > L[low])                   //相邻两位比较大小
			{
				int exp = L[tmp];
				L[tmp] = L[low];
				L[low] = exp;
			}
		}                     
	} 
	return low;                                   //返回此时位置
}
//改进方式,直接赋值
/*int Partition(SqList &L,int low,int high)         //返回枢轴所在位置,它之前的小于它
{                                                 //之后的大于它
	int key = L[low];                             //枢轴记录关键字
	while(low < high)                             //判别条件,不满足时结束
	{
		while(low < high && L[high] >= key )      //若右边的大于枢轴
		{
			high--;                               //向前比较
		}
		L[low] = L[high];                         //否则赋值
		while(low < high && L[low] <= key)        //若左边的小于枢轴
		{
			low++;                                //向后比较
		}
		L[high] = L[low];                         //否则赋值
	}
	L[low] = key;                                 //此时low = high,即可等价为L[high] = key,枢轴记录到位
	return low;                                   //返回此时位置
}*/

//交换方式
/*int Partition(SqList &L,int low,int high)
{
	int key = L[low];
	while(low < high)
	{
		while(low < high && L[high] >= key )
		{
			high--;
		}
		int tmp = L[low];
		L[low] = L[high];
		L[high] = tmp;
		while(low < high && L[low] <= key)
		{
			low++;
		}
		tmp = L[low];
		L[low] = L[high];
		L[high] = tmp;
	}
	return low;
}*/

void QuickSort(SqList &L,int low,int high)        //快速排序
{
	bool left = Left(L,low,high);
	bool right = Right(L,low,high) ;
	if(low < high)
	{
		int prvitloc = Partition(L,low,high);         //将数组一分为二
		if(!left)                                     //若左半部分没有进行数值交换
		{
			QuickSort(L,low,prvitloc-1);              //左半部分排序
		}
		if(!right)                                    //若右半部分没有进行数值交换
		{
			QuickSort(L,prvitloc+1,high);             //右半部分排序
		}
	}
}

int SelectMinKey(SqList &L,int n,int key)         //选择第key小的记录下标     
{
	for(int k = key+1;k < n;++k)                  //只比较key之后的
	{
		if(L[k] < L[key])                         //若小于则记录下标
		{
			key = k;
		}
	}
	return key;                                   //返回下标
}

void SelectSort(SqList &L,int n)                  //简单选择排序
{
	for(int i = 0;i < n-1;++i)
	{
		int j = SelectMinKey(L,n,i);              //第key小的记录位置
		if(i != j)                                //若不为此位置数,则交换位置
		{
			int tmp = L[i];
			L[i] = L[j];
			L[j] = tmp;
		}
	}
}

void Heapify(SqList &L,int low,int high)
{
	int sq = L[low];                         //将根结点保存在sq中
	for(int j = 2*low;j <= high;j *= 2)      
	{
		if(j < high && L[j] < L[j+1])        //沿关键字较大的孩子结点向下筛选
		{
			j++;                             //关键字较大节点下标
		}
		if(sq > L[j])                        //若孩子结点的值小于根结点的值,则不进行交换
		{
			break;
		}
		L[low] = L[j];
		low = j;
	}
	L[low] = sq;                             //将根结点插入到正确位置
}


void BuildHeap(SqList &L,int n)         //建立大顶堆
{
	for(int i = n/2;i > 0;i--)          //从序号n/2开始建立大顶堆
	{
		Heapify(L,i,n);
	}
}


void HeapSort(SqList &L,int n)
{                                       //对L[1..n]进行堆排序,不妨用L[0]做暂存单元
	BuildHeap(L,n);                     //将L[1-n]建成初始堆
	for(int i = n-1;i > 1;i--){ 
		                                //对当前无序区L[1..i]进行堆排序,共做n-1趟。
		L[0]=L[1];
		L[1]=L[i];
		L[i]=L[0];
		                                //将堆顶和堆中最后一个记录交换
		Heapify(L,1,i-1);
		                                //将L[1..i-1]重新调整为堆,仅有L[1]可能违反堆性质
	} 
} 

void main()
{
	SqList sq = {0,53,24,35,56,32,78,99}; 
	SqList sq2 = {53,24,35,56,32,78,99}; 
	for(int i = 0;i < 7; ++i)
	{
		cout<<sq2[i]<<" ";
	}
	cout<<endl;
	BubbleSort(sq2,7);                          //冒泡排序结果打印
	for(i = 0;i < 7; ++i)
	{
		cout<<sq2[i]<<" ";
	}
	cout<<endl;
	QuickSort(sq2,0,6);                         //快速排序
	for(i = 0;i < 7; ++i)
	{
		cout<<sq2[i]<<" ";
	}
	cout<<endl;
	SelectSort(sq2,7);                         //简单选择排序
	for(i = 0;i < 7; ++i)
	{
		cout<<sq2[i]<<" ";
	}
	cout<<endl;
	HeapSort(sq,8);
	for(i = 1;i < 8; ++i)
	{
		cout<<sq[i]<<" ";
	}
	cout<<endl;
}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值