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

交换排序:利用交换数据元素位置的方法进行排序的方法

一、冒泡排序

基本思想:将序列中第一个记录与第二个记录比较,若前一个大于后一个,则交换位置。然后比较第二个和第三个,第三个和第四个,以此类推,一轮之后,序列中最大的元素就到了序列最后的位置上。继续进行第2轮,第3轮,第n-1轮。若其中某一轮途中没有元素交换,则证明序列已经排好序,后面的轮次不需要再进行。冒泡排序是稳定的排序。

排序过程如图所示:

C++代码:

#include<iostream>
using namespace std;

int * bubbleSort(int *a, int length) {
	int i, j, change;
	//记录当前轮次中有没有元素交换
	change = 1;
	j = length - 1;
	while (j > 0 && change) {
		change = 0;
		for (i = 0; i < j; i++) {
			if (a[i] > a[i + 1]) {
				//交换
				int temp = a[i];
				a[i] = a[i+1];
				a[i + 1] = temp;
				change = 1;
			}
		}
	}
	return a;
}

int main() {
	int length = 10;
	int a[10] = { 65,34,25,12,56,14,92,23,87,46 };
	int number = 3;
	int d[3] = {5,3,1};
	cout << "排序前:";
	for (int i = 0; i < length; i++) {
		cout << a[i] << " ";
	}
	cout << endl;
	int *p = bubbleSort(a,length);
	cout <<endl<< "排序后:";
	for (int i = 0; i < length; i++) {
		cout << p[i] << " ";
	}
	system("pause");
	return 0;
}

 

空间复杂度:Ο(1)

时间复杂度:Ο(n^2)

 

二、快速排序

快速排序又叫分区交换排序,它是对冒泡排序的一种改进,是目前已知排序方法中最快的一种。

基本思想:从待排序的序列中选取一个元素R(一般选取第一个)作为标准,调整所有记录的位置,使得R之前的记录均小于R,R之后的记录均大于R,即一个快速排序之后,R被放到了最终的位置上。同时,R把原序列划分为两个子序列,对两个子序列继续使用该方法,直到所有子序列的长度为1时排序完成。快速排序是一个递归的过程。快速排序是不稳定的排序。

排序过程图示:

 

C++代码:

#include<iostream>
using namespace std;

//快速排序
//分割(单次快排,寻找标准元素的位置)
int Partition(int a[], int low, int high) {
	int temp = a[low];//当前需要寻找位置的数据元素
	while (low < high) {
		while (low < high && a[high]>=temp) {
			high--;
		}
		//将小于标准元素的数据往前放
		if (a[high] < temp) {
			a[low] = a[high];
			low++;
		}
		
		while (low < high && a[low]<=temp) {
			low++;
		}
		//将大于标准元素的数据往后放
		if (a[low] > temp) {
			a[high] = a[low];
			high--;
		}
	}
	a[low] = temp;   //标准元素移动到正确的位置
	return low;  //返回标准位置
}

//快速排序
//排序
void QSort(int a[], int low, int high){
	int standardLocation;
	if (low < high) {
		standardLocation = Partition(a, low, high);
		cout << "standardLocation=" << standardLocation << ",low=" << low << ",high=" << high << endl;
		cout << "排序中间结果:";
		for (int i = 0; i < 10; i++) {
			cout << a[i] << " ";
		}
		cout << endl;
		QSort(a, low, standardLocation-1);
		QSort(a, standardLocation+1, high);
	}
	
}

int * QuickSort(int a[], int length) {
	QSort(a, 0, length-1);
	return a;
}


int main() {
	int length = 10;
	int a[10] = { 65,34,25,12,56,14,92,23,87,46 };
	int number = 3;
	int d[3] = {5,3,1};
	cout << "排序前:";
	for (int i = 0; i < length; i++) {
		cout << a[i] << " ";
	}
	cout << endl;

	int *p = QuickSort(a, length);
	cout << endl << "排序后:";
	for (int i = 0; i < length; i++) {
		cout << p[i] << " ";
	}
	system("pause");
	return 0;
}

 

空间复杂度:Ο(n)

时间复杂度:Ο(nlog_2⁡n)

 

快速排序复杂度分析:

时间复杂度:快速排序的时间复杂度取决于标准记录的选择。

a.最快的情况

如果每次选的标准记录都是中间数,则序列总是被分为长度基本相等的子序列。若完成n个记录排序所需时间为T(n),则有:

其中k表示分解的次数,这种情况下分解过程可以描述为一颗满二叉树,分解的次数为树的深度log_2⁡n。所以有:

b.最坏的情况

如果每次选择的记录都是当前序列的最小数,则总是把序列分为一个空子序列和一个长度为原长度减一的子序列,这时,总比较次数为:

 

若原始记录时已经排好序(与要求的顺序相反)的序列,且每次选取的是第一个作为标准元素,快速排序则变成了时间复杂度为Ο(n^2)的慢排序。但是一般情况下,待排序的是随机的,所以快速排序的平均比较次数为Ο(nlog_2⁡n),由于快速排序元素的移动次数和比较次数相比少很多,故快速排序的时间复杂度为Ο(nlog_2⁡n)

空间复杂度:递归式快速排序需要环境栈存储分割点,栈的深度最好情况下为log_2⁡n,最坏情况下为n,因此快速排序的空间复杂度为O(n)。

 

快速排序不稳定性举例

例如(5,3A,6,3B)对这个进行排序,排序之前相同的数3A与3B,A在B的前面,经过排序之后会变成

        (3B,3A,5,6),所以说快速排序是一个不稳定的排序

 

 

三、快速排序的非递归形式

用堆栈存储中间数据,代替递归。栈结构可以用数组模拟

#include<iostream>
using namespace std;

//快速排序
//分割(单次快排,寻找标准元素的位置)
int Partition(int a[], int low, int high) {
	int temp = a[low];//当前需要寻找位置的数据元素
	while (low < high) {
		while (low < high && a[high]>=temp) {
			high--;
		}
		//将小于标准元素的数据往前放
		if (a[high] < temp) {
			a[low] = a[high];
			low++;
		}
		
		while (low < high && a[low]<=temp) {
			low++;
		}
		//将大于标准元素的数据往后放
		if (a[low] > temp) {
			a[high] = a[low];
			high--;
		}
	}
	a[low] = temp;   //标准元素移动到正确的位置
	return low;  //返回标准位置
}

//快速排序—非递归形式
int * QuickSort_NonRecursive(int a[], int length) {
        //用数组模拟栈结构
	int  *stack = new int[length]; 
	int top = 0; 
	int low = 0; 
	int high = length - 1; 
	int par = Partition(a, low, high);
	//  入栈 
	if(par > low+1){ 
		stack[top++] = low;
		stack[top++] = par-1; 
	}
	if(par < high-1){ 
		stack[top++] = par+1;
		stack[top++] = high; 
	} 
	//出栈 
	while(top > 0){ 
		high = stack[--top];
		low = stack[--top]; 
		par = Partition(a, low, high); 
		//再入栈 
		if(par > low+1){ 
			stack[top++] = low; 
			stack[top++] = par-1; 
		} 
		if(par < high-1){ 
			stack[top++] = par+1; 
			stack[top++] = high; 
		} 
	} 
	return a;
}


int main() {
	int length = 10;
	int a[10] = { 65,34,25,12,56,14,92,23,87,46 };
	int number = 3;
	int d[3] = {5,3,1};
	cout << "排序前:";
	for (int i = 0; i < length; i++) {
		cout << a[i] << " ";
	}
	cout << endl;

	int *p = QuickSort_NonRecursive(a, length);
	cout << endl << "排序后:";
	for (int i = 0; i < length; i++) {
		cout << p[i] << " ";
	}
	system("pause");
	return 0;
}

相关文章

https://mp.csdn.net/postedit/87636287  十大排序算法对比与总结

参考博客:https://blog.csdn.net/qq_39475906/article/details/80338568

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值