C++实现常用的排序算法

上一篇博文中提到 “快速寻找满足条件的两个数” 问题需要分别用到排序和查找两个函数,那么这里就系统地介绍下C++中一些常用的排序算法 (略去上一篇博文中的“快速排序”算法)。

一、交换排序

1. 冒泡排序:

这个算法的名字由来是因为越小(大)的元素会经由交换慢慢“浮”到数列的顶端。它重复地访问所要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。直到没有再需要交换,也就是说该数列已经排序完成。

//冒泡排序
void bubbleSort(int arr[],int n) 
{
	int i, j, temp;
	bool isChanged;	//记录此次遍历是否有数值的交换
	for (i = 0; i < n - 1; i++)	//i用于控制循环次数并记录已排好序的数列长度
	{
		for(j = 0; j < n - i - 1; j++)	//j用于对该数列未排好序部分进行遍历控制
		{
			isChanged = false;
			//把最大的那个数“沉”到数列的最底端
			if (arr[j + 1] < arr[j])
			{
				temp = arr[j + 1];
				arr[j + 1] = arr[j];
				arr[j] = temp;
				isChanged = true;		//发生数值交换
			}
		}
		//未发生数值交换,说明数列已完成排序
		if (false == isChanged)
		{
			break;
		}
	}
}

 2. 快速排序

快速排序是对冒泡排序的一种改进。它的基本思想是:通过一趟排序将要排序的数据分割成独立的两部分,其中一部分的所有数据都比另外一部分的所有数据都要小,然后再按此方法对这两部分数据分别进行快速排序,整个排序过程可以递归进行,以此达到整个数据变成有序序列。

**代码略(见上一篇博客)

二、插入排序

1.直接插入排序

将数组分为无序区和有序区两个区,然后不断将无序区的第一个元素按大小顺序插入到有序区中去,最终将所有无序区元素都移动到有序区完成排序。直接插入排序与打扑克时整理手上的牌非常类似。摸来的第1张牌无须整理,此后每次从桌上的牌(无序区)中摸最上面的1张并插入左手的牌(有序区)中正确的位置上。为了找到这个正确的位置,须自左向右(或自右向左)将摸来的牌与左手中已有的牌逐一比较。

//直接插入排序
void insertSort(int arr[],int n)
{
	int i, j, temp;
	for (i = 0; i != n - 1; i++)	//记录有序区的大小
	{
		if (arr[i + 1] < arr[i])
		{
			j = i;
			temp = arr[i + 1];
			do 
			{
				arr[j + 1] = arr[j];	//将数值大于temp的记录后移
				j--;
			} while (temp < arr[j] && j >= 0);	//比较大小并判断数组边界
			arr[j + 1] = temp;
		}
	}
}

2. 希尔排序

先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为d1的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<d(t-l)<…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。

//希尔排序
void shellSort(int arr[],int n)
{
	int gap; //增量,即"d"
	for(gap = n / 2; gap > 0; gap = gap / 2)	//缩小增量
	{
		//在各组内进行直接插入排序
		for(int i = 0; i < gap; i++)	//arr[0]~arr[gap-1]为每个组的首元素
		{
			for(int j = i + gap; j < n; j = j + gap)	//对所有距离为gap的倍数的记录进行操作
			{
				if(arr[j] < arr[j - gap])
				{
					int temp = arr[j];
					int k = j - gap;
					while(k >= 0 && arr[k] > temp)
					{
						arr[k + gap] = arr[k];
						k = k - gap;
					}
					arr[k + gap] = temp;
				}
			}
		}
	}
}

三、选择排序

1. 直接选择排序

直接选择排序也是一种简单的排序方法,它的基本思想是:第一次从R[0]~R[n-1]中选取最小值,与R[0]交换,第二次从R[1]~R[n-1]中选取最小值,与R[1]交换...

//直接选择排序
void selectSort(int arr[],int n)
{
	int i, j, k, temp;
	for (i = 0; i != n - 1; i++)
	{
		k = i;
		for (j = i + 1; j != n; j++)
		{
			if (arr[j] < arr[k])
			{
				k = j;
			}
		}
		temp = arr[i];
		arr[i] = arr[k];
		arr[k] = temp;
	}
}

2. 堆排序

堆排序是指利用堆积树(堆)这种资料结构所设计的一种排序算法,可以利用数组的特点快速定位指定索引的元素。

**具体代码部分将在以后的博客中详解。

四、归并排序

归并排序是建立在归并操作上的一种有效的排序算法。该算法是采用分治法的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。

**具体代码部分将在以后的博客中详解。

五、基数排序

基数排序属于“分配式排序”,有最高位优先(Most Significant Digit first)法,简称MSD法和最低位优先(Least Significant Digit first)法,简称LSD法。其原理是将整数按位数切割成不同的数字,然后按每个位数分别比较。

**具体代码部分将在以后的博客中详解。

--------------------我---是---分---割---线--------------------

各种排序算法性能比较

1. 稳定性比较:

稳定的:基数排序、冒泡排序、直接插入排序、折半插入排序、归并排序

不稳定的:快速排序、希尔排序、堆排序、直接选择排序

2. 时间复杂度比较:

3. 空间复杂度比较:

空间性能是排序算法所需辅助空间大小

  1) 所有简单排序和堆排序都是O(1)
  2) 快速排序为O(log2n),要为递归程序执行过程中的栈分配所需的辅助空间
  3) 归并排序和基数排序所需辅助空间最多,为O(n)

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值