算法——几个经典排序算法

归并排序

归并排序是利用"归并"技术来进行排序。归并是指将若干个已排序的子文件合并成一个有序的文件。

特点:
最差时间复杂度:O(nlogn)
平均时间复杂度:O(nlogn)
最差空间复杂度:O(n)
稳定性:稳定
算法步骤:
1.申请两个与已经排序序列相同大小的空间,并将两个序列拷贝其中;
2.设定最初位置分别为两个已经拷贝排序序列的起始位置,比较两个序列元素的大小,依次选择相对小的元素放到原始序列;
3.重复2直到某一拷贝序列全部放入原始序列,将另一个序列剩下的所有元素直接复制到原始序列尾。
示意图:
在这里插入图片描述
合并相邻有序子序列流程图:
在这里插入图片描述
代码:

	/*
	* 归并排序(从上往下)
	*/
void mergeSortUp2Down(vector<int> & a, int start, int end) {
		if (start >= end)
			return;
		int mid = (start + end) >> 1;
	
		mergeSortUp2Down(a, start, mid);
		

		mergeSortUp2Down(a, mid + 1, end);
		

		merge(a, start, mid, end);
	
	}

	/*
	* 将一个数组中的两个相邻有序区间合并成一个
	*/
 void merge(vector<int> &a, int start, int mid, int end) {
		vector<int> tmp (end - start + 1,0);//创建临时数组

		int i = start, j = mid + 1, k = 0;
		while (i <= mid && j <= end) {
			if (a[i] <= a[j])
				tmp[k++] = a[i++];
			else 
				tmp[k++] = a[j++];
		}

		while (i <= mid)
			tmp[k++] = a[i++];
		while (j <= end)
			tmp[k++] = a[j++];
		for (k = 0; k < tmp.size(); k++)
			a[start + k] = tmp[k];//改变原来数组排序
	}

快速排序

快速排序,说白了就是给基准数据找其正确索引位置的过程.
   如下图所示,假设最开始的基准数据为数组第一个元素23,则首先用一个临时变量去存储基准数据,即tmp=23;然后分别从数组的两端扫描数组,设两个指示标志:low指向起始位置,high指向末尾.
在这里插入图片描述
首先从后半部分开始,如果扫描到的值大于基准数据就让high减1,如果发现有元素比该基准数据的值小(如上图中18<=tmp),就将high位置的值赋值给low位置 ,结果如下:
在这里插入图片描述
然后开始从前往后扫描,如果扫描到的值小于基准数据就让low加1,如果发现有元素大于基准数据的值(如上图46=>tmp),就再将low位置的值赋值给high位置的值,指针移动并且数据交换后的结果如下:

在这里插入图片描述
然后再开始从后向前扫描,原理同上,发现上图11<=tmp,则将low位置的值赋值给high位置的值,结果如下:
在这里插入图片描述
然后再开始从前往后遍历,直到low=high结束循环,此时low或high的下标就是基准数据23在该数组中的正确索引位置.如下图所示.

在这里插入图片描述
 这样一遍走下来,可以很清楚的知道,其实快速排序的本质就是把基准数大的都放在基准数的右边,把比基准数小的放在基准数的左边,这样就找到了该数据在数组中的正确位置.
  以后采用递归的方式分别对前半部分和后半部分排序,当前半部分和后半部分均有序时该数组就自然有序了。
  
一些小结论

从上面的过程中可以看到:

①先从队尾开始向前扫描且当low < high时,如果a[high] > tmp,则high–,但如果a[high] < tmp,则将high的值赋值给low,即arr[low] = a[high],同时要转换数组扫描的方式,即需要从队首开始向队尾进行扫描了
  ②同理,当从队首开始向队尾进行扫描时,如果a[low] < tmp,则low++,但如果a[low] > tmp了,则就需要将low位置的值赋值给high位置,即arr[low] = arr[high],同时将数组扫描方式换为由队尾向队首进行扫描.
  ③不断重复①和②,知道low>=high时(其实是low=high),low或high的位置就是该基准数据在数组中的正确索引位置.

代码:

//快速排序
void quicksort(int left, int right) {
	int i, j, t, temp;
	if(left > right)
		return;
    temp = a[left]; //temp中存的就是基准数
    i = left;
    j = right;
    while(i != j) { //顺序很重要,要先从右边开始找
    	while(a[j] >= temp && i < j)
    		j--;
    	while(a[i] <= temp && i < j)//再找右边的
    		i++;       
    	if(i < j)//交换两个数在数组中的位置
    	{
    		t = a[i];
    		a[i] = a[j];
    		a[j] = t;
    	}
    }
    //最终将基准数归位
    a[left] = a[i];
    a[i] = temp;
    quicksort(left, i-1);//继续处理左边的,这里是一个递归的过程
    quicksort(i+1, right);//继续处理右边的 ,这里是一个递归的过程
}


参考博客:
[1]归并排序(分治法)
[2]十大经典排序算法(动图演示)
[3]快速排序

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值