排序算法(三)、交换排序 —— 冒泡排序 和 快速排序

1、冒泡排序

C 程序如下:

// 冒泡排序
void sort2(int a[], int n)
{
	for (int i = 0; i < n - 1; i++)
	{
		for (int j = 0; j < n - 1- i ; j++)
		{
			if (a[j] > a[j + 1])
				
			{
				swap(a[j], a[j + 1]);
			}
		}
	}

}

复杂度分析:空间复杂度为 O(1),最坏时间复杂度为 O(n^2),最好情况下时间复杂度为 O(n).平均时间复杂度为 O(n^2)。冒泡排序显然是一种稳定的排序方法。

2、快速排序

快速排序是冒泡排序的一种改进。它的基本思想是基于分治法的:在待排序表 L[1.....n] 中任取一个元素 pivot 作为基准通过一趟排序,将 L 分成两个部分L[1......k-1] 和 L[k+1...n],使得L[1......k-1] 中的所有元素都小于等于 pivot,  L[k+1...n] 都大于 pivot 。最终,pivot 就放在了 L(k) 的位置。这个过程称为一趟快速排序。然后,递归地对两个子表重复上述过程,直到每部分只有一个元素或者为空。此时,所有的元素都放在了应该放的位置。

假设划分算法已知,为partition(),那么,递归调用算法为:

void QuickSort(int A[], int low, int high)
{
	if (low < high)
	{
		int pivotpos = Partition(A,low,high);
		QuickSort(A,low,pivotpos - 1);
		QuickSort(A,pivotpos +1,high);
	}
}
而最难的划分算法

1)第一种思路:两个下标分别从首、尾向中间扫描

此种方法,表中的第一个元素作为基准元素 pivot ,则表中比 pivot 大的向右移动,比 pivot 小的向左移动

C 程序如下:

//快速排序

int Partition(int A[], int low, int high)
{
	int pivotpos = A[low];  // 当前表的第一个元素作为基准值
	while (low < high)  // 循环跳出的条件
	{
		while (low < high && A[high] > pivotpos)  // 比基准值小的元素往左移动
			--high;
		A[low] = A[high];    

		while (low < high && A[low] < pivotpos)  // 比基准值大的往右移动
			++low;
		A[high] = A[low];
	}
	A[low] = pivotpos;  // 基准值最终存放的位置
	return low;   // 返回基准位置
}

void QuickSort(int A[], int low, int high)
{
	if (low < high)
	{
		int pivotpos = Partition(A,low,high);
		QuickSort(A,low,pivotpos - 1);
		QuickSort(A,pivotpos +1,high);
	}
}

int main()
{
	int a[] = { 1, 3, 5, 7,12,0,56,4, 2 ,6};
	int len = (int)sizeof(a) / sizeof(*a);
	//sort2(a,len);

	QuickSort(a, 0, len -1);

	for (int i = 0; i < len; i++)
		cout << a[i] << endl;
	return 0;
}

举个例子,

待排序列38712564
第1次2871 564
第2次2 718564
第3次217 8564
第4次21 78564
第5次21378564

一个萝卜一个坑,第一次,将‘2’挖出,放到原来 ‘3’那个坑里面。2 那个坑就需要 8 去补。。。依次类推,最后,基准元素 3 就被放到了第 三 个位置。

(2)第二种思路:两个指针一前一后逐步向后扫描

C 代码

int partition2(int a[], int p, int r)
{
	int x = a[r];  // 选择最后一个元素作为基准
	int i = p - 1;  // i 初始值是第一个元素的之前的位置。i 一直指向的是比基准元素小的那个值
	for (int j = p; j < r; j++) // j 从第一个元素开始往后遍历
	{
		if (a[j] <= x)
		{
			++i;  // 如果有比基准小的,就将 i 向后移动一个,代表元素个数
			swap(a[i],a[j]);
		}
	}
	swap(a[i + 1], a[r]);
	return (i + 1);
}

void QuickSort(int A[], int low, int high)
{
	if (low < high)
	{
		//int pivotpos = Partition(A,low,high);
		int pivotpos = partition2(A, low, high);
		QuickSort(A,low,pivotpos - 1);
		QuickSort(A,pivotpos +1,high);
	}
}

int main()
{
	int a[] = {1,3,4,2,67,45,21};
	QuickSort(a,0,6);
	for (int i = 0; i < 7; i++)
	{
		cout << a[i] << endl;;
	}

	return 0;
}

复杂度分析:

1、2013 腾讯

题目描述:一个数组中存储有且仅有大写和小写字母,编写一盒函数对数组内的字母重新排列,让小写字母在大写字母之前;

分析:可以使用快速排序的一次快排

bool isupper(char c)
{
	if (c >= 'A' && c <= 'Z')
		return true;
	return false;
}

bool islower(char c)
{
	if (c >= 'a' && c <= 'z')
		return true;
	return false;
}

void partition(char str[], int low, int high)
{
	while (low < high)
	{
		while (low < high &&  isupper(str[high]))
			--high;
		while (low < high && islower(str[low]))
			++low;
		char c_temp = str[high];
		str[high] = str[low];
		str[low] = c_temp;
	}
}

int main()
{
	char str[] = {'a','A','Z','d','B','s','b'};
	partition(str,0,6);
	cout << str;

	return 0;
}

一些说明:形参可以使用 string 类型,但是需要利用引用 & 类型,如:

void partition(string str, int low, int high)

2、



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值