C++常用排序算法

参考

参考

冒泡排序

比较相邻的元素。如果第一个比第二个大,就交换他们两个。

void BubbleSort_orderly(vector<int>& v) {
	int len = v.size();
	bool orderly = false;
	for (int i = 0; i < len - 1 && !orderly; ++i) {
		orderly = true;
		for (int j = 0; j < len - 1 - i; ++j) {	//每for一次,得到的v[len-1-i]是最大的
												//例如v[len - 1]是所有元素最大的
												//v[len-1-1]是所有元素中倒数第二大的
			if (v[j] > v[j + 1]) {  // 从小到大 //从来没有进去下面指令代表已经有序了
				orderly = false;	// 发生交换则仍非有序
				swap(v[j], v[j + 1]);
			}
		}
	}
}

选择排序

在未排序序列中找到最小(大)元素,存放到排序序列的起始位置

void SelectionSort(vector<int>& v) {
	int min, len = v.size();
	for (int i = 0; i < len - 1; ++i) {
		min = i;		//第一个作为最小的
		for (int j = i + 1; j < len; ++j) {	//每for一次找到一个最小值
			if (v[j] < v[min]) {    // 标记最小的
				min = j;		//更新
			}
		}
		if (i != min)  // 交换到前面
			swap(v[i], v[min]);
	}
}

插入排序

1.从第一个元素开始,该元素可以认为已经被排序
2.取出下一个元素,在已经排序的元素序列中从后向前扫描
3.如果该元素(已排序)大于新元素,将该元素移到下一位置
4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
5.将新元素插入到该位置后
6.重复步骤2~5

void InsertSort(vector<int>& v)
{
    int len = v.size();
	for (int i = 1; i < len; ++i) {
		int temp = v[i];
        for(int j = i - 1; j >= 0; --j)		//循环已排序好的元素
        {
            if(v[j] > temp)		//将排序后的序列的每一个值与当前值比较
            {
                v[j + 1] = v[j];
                v[j] = temp;
            }
            else
                break;
        }
	}
}

希尔排序

希尔排序这个名字,来源于它的发明者希尔,也称作“缩小增量排序”,是插入排序的一种更高效的改进版本。我们知道,插入排序对于大规模的乱序数组的时候效率是比较慢的,因为它每次只能将数据移动一位,希尔排序为了加快插入的速度,让数据移动的时候可以实现跳跃移动,节省了一部分的时间开支。
希尔排序:每一轮按照事先决定的间隔进行插入排序,间隔会依次缩小,最后一次一定要是1。
可能你会问为什么区间要以 gap = gap*3 + 1 去计算,其实最优的区间计算方法是没有答案的,这是一个长期未解决的问题,不过差不多都会取在二分之一到三分之一附近。

例:6 4 3 7 5 1 2
gap = gap*3 + 1										gap = gap*2 + 1(也可以)
while (h < length / 3) {									while (h < length / 2) {
        h = 3 * h + 1;											h = 2 * h + 1;	
    }													}
得h = 4,												得h = 3
又h = h/3;												h = h/2;
得h=1
又j -= h
如果array[j] < array[j - h],将会从右到左继续比较
template<typename T>
void shell_sort(T array[], int length) {
	int h = 1;
	while (h < length / 3) {
		h = 3 * h + 1;
	}
	//①或者直接用
	if (length % 2 == 0)
		h = length / 2;
	else
		h = length / 2 + 1;

	while (h >= 1) {
		for (int i = h; i < length; i++) {
			for (int j = i; j >= h && array[j] < array[j - h]; j -= h) {	//从后往前遍历
				std::swap(array[j], array[j - h]);
			}
		}
		h = h / 3;
		//②或 h = h / 2;
	}
}

归并排序

归并字面上的意思是合并,归并算法的核心思想是分治法,就是将一个数组一刀切两半,递归切,直到切成单个元素,然后重新组装合并,单个元素合并成小数组,两个小数组合并成大数组,直到最终合并完成,排序完毕。

template<typename T>
void merge_sort_recursive(T arr[], T reg[], int start, int end) {
	if (start >= end)
		return;
	int len = end - start, mid = (len >> 1) + start;//len >> 1等同于除以2
	int start1 = start, end1 = mid;
	int start2 = mid + 1, end2 = end;
	merge_sort_recursive(arr, reg, start1, end1);
	merge_sort_recursive(arr, reg, start2, end2);
	int k = start;
	while (start1 <= end1 && start2 <= end2)	//小值往前排
		reg[k++] = arr[start1] < arr[start2] ? arr[start1++] : arr[start2++];
	while (start1 <= end1)//如果第一个while是后面的为小值,那么前面的值往后面排
		reg[k++] = arr[start1++];
	while (start2 <= end2)	//如果第一个while是前面的为小值,那么排序不变
		reg[k++] = arr[start2++];
	for (k = start; k <= end; k++)	//将排序好的数组赋值给源数组
		arr[k] = reg[k];
}

快速排序

1.选取第一个数为基准
2.将比基准小的数交换到前面,比基准大的数交换到后面
3.对左右区间重复第二步,直到各区间只有一个数

void QuickSort(vector<int>& v, int low, int high) { //从小到大排序
	if (low >= high)		// 结束标志
		return;
	int first = low;		// 低位下标
	int last = high;		// 高位下标
	int key = v[first];		// 设第一个为基准

	while (first < last)//确定key的下标
	{
		// 将比第一个小的移到前面(如果是从大到小排序,v[last] <= key)
		while (first < last && v[last] >= key)	//循环直到找到一个比key小的值
			last--;
		if (first < last)
			v[first++] = v[last];	//因为first的位置已经更新,所以得++

		// 将比第一个大的移到后面(如果是从大到小排序,v[last] >= key)
		while (first < last && v[first] <= key) //循环直到找到一个比key大的值
			first++;
		if (first < last)
			v[last--] = v[first];	因为last的位置已经更新,所以得--
	}	//每一次循环的目的是为了得到一个固定下标的值
	// 基准置位
	v[first] = key;	//得到的值不会再改变,下标已经固定死了
	// 前半递归
	QuickSort(v, low, first - 1);	//first之前的递归排序
	// 后半递归
	QuickSort(v, first + 1, high);	//first之后的递归排序
}

堆排序

堆排序顾名思义,是利用堆这种数据结构来进行排序的算法。堆是一种优先队列,两种实现,最大堆和最小堆,由于我们这里排序按升序排,所以就直接以最大堆来说吧。
我们完全可以把堆(以下全都默认为最大堆)看成一棵完全二叉树,但是位于堆顶的元素总是整棵树的最大值,每个子节点的值都比父节点小,由于堆要时刻保持这样的规则特性,所以一旦堆里面的数据发生变化,我们必须对堆重新进行一次构建。
既然堆顶元素永远都是整棵树中的最大值,那么我们将数据构建成堆后,只需要从堆顶取元素不就好了吗? 第一次取的元素,是否取的就是最大值?取完后把堆重新构建一下,然后再取堆顶的元素,是否取的就是第二大的值? 反复的取,取出来的数据也就是有序的数据。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值