数据结构复习笔记01_排序算法_交换排序

基于交换的排序方法主要有①冒泡排序和②快速排序。文章默认排序算法是升序

一、冒泡排序

基本思想:两两比较和交换,每次冒出一个关键字最大的记录。一般有两层循环,一般用两层for循环,外层循环只是指定这一趟已经有i个已冒出的数字(从而指定内层遍历的终点),内层循环j是遍历元素、比较、交换,直到n-i,循环结束条件是有一趟内层循环未发生交换,则证明有序。

eg:

原始序列:12, 34, 20, 15, 9, 25, 27, 13

第一趟: 12 34 20 15 9 25 27 13

             12 20 34 15 9 25 27 13 

             12 20 15 34 9 25 27 13

             12 20 15 9 34 25 27 13

             ……

             12 20 15 9 25 27 13 34

第二趟: 12 15 9 20 25 13 27 24

第三趟: 12 9 15 20 13 25 27 34

第四趟: 9 12 15 13 20 25 27 34

第五趟: 9 12 13 15 20 25 27 34

第六趟: 9 12 13 15 20 25 27 34

代码:

//冒泡
void BubbleSort(double R[], int length)
{
	for (int i = 1; i < length; ++i)
	{
		bool swap = false;
		for (int j = 0; j < length - i; ++j)
		{
			if (R[j] > R[j + 1])    //比较、交换
			{
				int temp = R[j];
				R[j] = R[j + 1];
				R[j + 1] = temp;
				swap = true;
			}
		}
		if (!swap) break;    //没发生交换说明有序,结束排序
	}
}

二、改进的冒泡排序(然并卵)

冒泡过程中如果后面的记录未发生交换,则证明后面的序列已经有序,常规冒泡还是会进行比较到结束位置。因此每次记录最后的交换位置,作为下次的比较终点。

eg:23 15 14 25 28 30

       15 14 23 25 28 30      //红色为最后交换时 j 的值

代码:

//改进的冒泡
//记录每一躺最后交换的j作为下一次冒泡的终点
void BubbleSortEx(double R[], int length)
{
	int i = length - 1;
	while (i > 1)
	{
		int lastIndex = 0;
		for (int j = 0; j < i; ++j)
		{
			if (R[j] > R[j + 1])
			{
				int temp = R[j];
				R[j] = R[j + 1];
				R[j + 1] = temp;
				lastIndex = j;
			}
		}
		i = lastIndex;
	}
}
实际提升效果有限,只有对特殊情况才有很好的效果。
性能方面,空间复杂度有一个临时变量作为交换空间,o(1)。

时间复杂度,最好情况,正序,比较n-1次,交换0次。最坏情况,逆序o(n^2),平均o(n^2)。是一种稳定排序

三、快速排序

基本思想是以某个记录的关键字作为基准(划分元),将整个序列划分成两组,左边的记录关键字小于等于划分元,右边的大于等于划分元,而划分元所处的位置就是它最终排序好的位置。一般选取当前记录的第一个记录作为划分元,然后利用递归思想快排左右的子记录,这种思想和二叉树遍历很相似,递归遍历他们的子树。

数据结构复习笔记01_排序算法_交换排序_第1张图片

代码:

//快排一次,返回划分元最终位置
int QuickPartition(double R[], int low, int high)
{
	//以左端为划分元
	double value = R[low];
	while (low < high)
	{
		int temp = 0;
		while (low < high && R[high] >= value) --high;    //high左移
		R[low] = R[high];    //比划分元小的值复制到左边,这里直接赋值不必担心覆盖,因为“被覆盖的值”已经保存在value
		while (low < high && R[low] <= value) ++low;    //low右移
		R[high] = R[low];    //比划分元大的值复制到右边
	}
	R[low] = value;    //i为划分元最终位置
	return low;
}
//对顺序表R[l...h]快排
void QuickSort(double R[], int low, int high)
{
	if (low < high)
	{
		int p = QuickPartition(R, low, high);
		QuickSort(R, low, p - 1);
		QuickSort(R, p + 1, high);
	}    //像极了二叉树先序遍历
}
性能方面,从空间复杂度来看,递归调用的层数与n个结点二叉树的深度相同,因此最好情况o(logn),最差o(n)。

时间复杂度一次划分需要o(n),最好o(nlogn),最坏情况有序或基本有序,退化为冒泡,o(n^2)。快排不是稳定排序


你可能感兴趣的:(c++,算法,数据结构)