C++实现各种排序(快速、归并、冒泡、选择、堆排序)

1. 快速排序

使用递归的方法。选取数组中任意一个值key作为比较(通常选取第一个值),然后数组先从后往前寻找第一个小于key的值,再从前往后寻找第一个大于key的值,交换这两个值的位置,继续前面的寻找。然后把第一个值(key)交换到两个子数组中间位置。现在两子数组,左边都小于key,右边都大于key。左右子数组再进行递归。

时间复杂度平均O(nlogn),最坏是Olog(n^2).

//快速排序
void Quick_Sort(int * arr, int left, int right) {
	int i =0, j = 0, k = 0;
	if (left > right) return;

	k = arr[left];
	i = left;
	j = right;

	while (i < j) {
		//先从右往左找到第一个小于key的值
		while (i < j && arr[j] >= k) {
			j--;
		}
		//再从左往右找第一个大于key的值
		while (i < j && arr[i] <= k){
			i++;
		}
		//两个都找到之后交换位置
		myswap(arr[i], arr[j]);
	}
	//然后交换第一位和左数组的最后一位
	myswap(arr[left], arr[i]);

	//现在左边数组都小于key,右边数组都大于key,两个子数组递归,注意:key值不要送进递归!
	Quick_Sort(arr, left, i - 1);
	Quick_Sort(arr, i + 1, right);
}
void myswap(int & a, int & b) {
	int val = 0;
	val = a;
	a = b;
	b = val;
}

2. 归并排序

需要一个辅助数组来存储局部交换之后的值,然后将辅助数组赋给原数组。时间复杂度是O(nlogn)不变。

//归并排序,vector操作,引用传递参数
void Merge_Sort(vector<int> & data) {
	if (data.size() == 0) return;
	int length = data.size();

	vector<int> copy(length, 0);//初始化与data同样大小的copy,全是0
								//for (int i = 0; i < length; i++){
								//    copy.push_back(data[i]);
								//}

	MergeSortCore(data, copy, 0, length - 1);
}
void MergeSortCore(vector<int> & data, vector<int> & copy, int start, int end) {
	if (start == end) {
		copy[start] = data[start]; //每一个数组值都会递归到这个地方,相当于将data数组赋值给copy数组。//拷贝初始化之后这个去掉也没事
		return;
	}
	int length = (end - start) / 2;//将数组拆成两部分
	//计算左右两部分中逆序数
	MergeSortCore(data, copy, start, start + length);
	MergeSortCore(data, copy, start + length + 1, end);

	int i = start + length; //分别从两个子数组的最末端开始,同时辅助数组copy也从两个相邻子数组的末端开始
	int j = end;
	int index = end;
	while (i >= start && j >= start + length + 1) {
		if (data[i] > data[j]) {
			copy[index--] = data[i--];//将大数放在末尾,相当于小到大排序
		}
		else copy[index--] = data[j--];
	}
	//有可能某一个子数组还有值,而另一个已经遍历完了,就把剩下的接着顺序复制到copy中子数组.
	for (; i >= start; i--) {
		copy[index--] = data[i];
	}
	for (; j >= start + length + 1; j--) {
		copy[index--] = data[j];
	}

	//更新原data数组,很重要
	for (int i = start; i <= end; i++) {
		data[i] = copy[i];
	}
}

3. 选择排序

思想:选数组第一个位置为最小值的位置,然后遍历后面数组zha找出实际最小值的位置,和第一个位置的值交换。然后选择数组第二个位置开始重复。

//选择排序
void Choose_Sort(int * arr, int length)
{
	int min;
	int temp;
	for (int i = 0; i < length-1; i++)
	{
		min = i;
		for (int j = i+1; j < length; j++)
		{
			if (arr[j] < arr[min])
			{
				min = j;
			}
		}
		if (i != min)
		{
			temp = arr[i];
			arr[i] = arr[min];
			arr[min] = temp;
		}
	}
}

4. 冒泡排序

比较相邻位置的数字,较大的值不断的往后面放。

void Bubble_Sort(int * arr, int length)
{
	int temp;
	for (int i = 0; i < length-1; i++) //此循环记录第几遍冒泡交换
	{
		for (int j = 0; j < length-i-1; j++)
		{
			if (arr[j] > arr[j+1])
			{
				temp = arr[j];
				arr[j] = arr[j + 1];
				arr[j + 1] = temp;
			}
		}
	}
}

5. 堆排序

时间复杂度O(nlogn),不稳定排序。

参考:http://www.cnblogs.com/skywang12345/p/3602162.html

void maxheap_down(int a[], int start, int end)
{
	int c = start;            // 当前(current)节点的位置
	int l = 2 * c + 1;        // 左(left)孩子的位置
	int tmp = a[c];            // 当前(current)节点的大小
	for (; l <= end; c = l, l = 2 * l + 1)
	{
		// "l"是左孩子,"l+1"是右孩子
		if (l < end && a[l] < a[l + 1])
			l++;        // 如果有左右两孩子中选择较大者,即m_heap[l+1]
		if (tmp >= a[l])
			break;        // 调整结束
		else            // 交换值
		{
			a[c] = a[l];
			a[l] = tmp;
		}
	}
}

/*
* 堆排序(从小到大)
*
* 参数说明:
*     a -- 待排序的数组
*     n -- 数组的长度
*/
void heap_sort_asc(int a[], int n)
{
	int i;

	// 从(n/2-1) --> 0逐次遍历非叶节点。遍历之后,得到的数组实际上是一个(最大)二叉堆。
	for (i = n / 2 - 1; i >= 0; i--)
		maxheap_down(a, i, n - 1);

	// 从最后一个元素开始对序列进行调整(将上面找到的堆顶最大值放在尾部)
    // 不断的缩小调整的范围直到第一个元素
	for (i = n - 1; i > 0; i--)
	{
		// 交换a[0]和a[i]。交换后,a[i]是a[0...i]中最大的。
		swap(a[0], a[i]);
		// 调整a[0...i-1],使得a[0...i-1]仍然是一个最大堆。
		// 即,保证a[i-1]是a[0...i-1]中的最大值。
		maxheap_down(a, 0, i - 1);
	}
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值