入门级的三种排序算法(比较,冒泡,快排)详讲

1. 比较排序
  比较排序是小白最容易想到的排序方法,从第一个元素开始,和后面所有元素依次进行比较,比第一个元素小,就将这两个元素交换,最后比完第一轮,第一个元素肯定是最小的了,然后从第二个元素开始,和后面所有元素比较,一轮比完,第二个元素是第二小的,同理,比完n-1(n为数组元素个数)轮,数组全部变得有序。比较排序是稳定的,也就是遇到值一样大的情况下不会发生交换,保持原来位置,其时间复杂度为O(n^2),代码如下:

#include <iostream>
using namespace std;

void swap(int* a,int* b){//交换 
	int temp=*a;
	*a=*b;
	*b=temp;
}

void Sort(int a[],int len){
	for(int i=0;i<len-1;i++){
		for(int j=i+1;j<len;j++){
			if(a[i]>a[j]){
				swap(a[i],a[j]);
			}
		}
	}
}

int main(){
	int a[10]={8,6,9,7,3,0,2,5,1,4};
	cout << "排序前的数组:" << endl;
	for(int i=0;i<10;i++){
		cout << a[i] << " ";
		if(i==9) cout << endl;
	}
	Sort(a,10);
	cout << "排序后的数组:" << endl;
	for(int i=0;i<10;i++){
		cout << a[i] << " ";
		if(i==9) cout << endl;
	}
	return 0;
}

2. 冒泡排序
  冒泡排序是很经典的一个排序算法,顾名思义,冒泡排序,就像水里冒水泡一样,从最底下慢慢升到最上面。冒泡排序是相邻元素进行比较,这样使最大值慢慢换到最后面去,所以,冒泡排序也得进行n-1趟,是稳定的,其时间复杂度为O(N^2),代码如下:

#include <iostream>
using namespace std;

void swap(int* a,int* b){//交换 
	int temp=*a;
	*a=*b;
	*b=temp;
}

void Sort(int a[],int len){
	for(int i=0;i<len-1;i++){
		for(int j=0;j<len-i-1;j++){
			if(a[j]>a[j+1]){
				swap(a[j],a[j+1]);
			}
		}
	}
}

int main(){
	int a[10]={8,6,9,7,3,0,2,5,1,4};
	cout << "排序前的数组:" << endl;
	for(int i=0;i<10;i++){
		cout << a[i] << " ";
		if(i==9) cout << endl;
	}
	Sort(a,10);
	cout << "排序后的数组:" << endl;
	for(int i=0;i<10;i++){
		cout << a[i] << " ";
		if(i==9) cout << endl;
	}
	return 0;
}

3. 快速排序
  快速排序简称快排,是最常用的排序方法,C++里面STL库中的sort()方法就是快排(进行了优化)。理解快速排序你首先得了解分治思想,即将一个大的复杂的问题分成几个小的容易解决的问题,当你把所有小问题解决后,这个大问题也就被解决了。那么说回快排,快排的思想就是:在待排序数组找到一个基准值,将待排序数组分成两段,第一段的值全小于这个基准值,第二段的值全大于这个基准值。然后重复这个操作将这直到整个数组都变得有序。即 “整体有序,局部无序”。其中,基准值得选取关系到快排的效率,快排的平均复杂度为 O(n*logn) 当数组完全逆序时,快排的复杂度会退化成 O(n^2)。关于基准值的选取(快排的优化)这里不做展开,一般我们都选取区间最最左端的元素作为基准值。
  那么我们的问题转化成,如何将区间分段?这也是快排的核心: 交叉扫描,将元素交换位置
举个例子:待排序数组为:8 6 9 7 3 0 2 5 1 4
此时,基准值flag=8,区间最左端下标left=0,最右端下标right=9;从右端right-9开始扫描(因为我们基准值选取的是最左边的元素值),4<8,代表4应该在8的左边,所以我们将其交换位置,数组变成:4 6 9 7 3 0 2 5 1 8,left=0,right=9然后从左边left=0开始扫,,4<=8,代表4应该在8的左边,位置正确,那么接着扫描,6<=8,代表6应该在8的左边,位置正确,那么接着扫描,9=>8,9应该在8的右边,j进行交换,数组变成:4 6 8 7 3 0 2 5 1 9,left=2,right=9,然后重复此操作(没交换,就继续向前(后)扫描,交换了就从另一边开始扫描),直到left>=right,就代表数组已经被分好段。分好段的数组为:4 6 1 7 3 0 2 5 8 9,分成了4 6 1 7 3 0 2 5和9这两个待排序区间,重复上面的操作,直至所有区间都排好序(每个元素的位置都正确),即排序完成。需要注意的是: 快排是不稳定的。根据上面的思路,我们可以写出下面的代码:
  代码如下:(内含详细注释)

#include <iostream>
using namespace std;

void swap(int *a,int *b){//交换
	int temp=*a;
	*a=*b;
	*b=temp;
}

int partition(int left,int right,int a[]){//使基准值左边全小于基准值,基准值右边全大于基准值 
	int flag=a[left];//基准值,一般选取区间最左边的元素 
	while(left<right){
		//先从后往前扫,如果比基准值小,将两个值交换 
		while(left<right && a[right]>=flag) right--;
		swap(&a[left],&a[right]);
		//然后从前往后扫,如果比基准值大,将两个值交换 
		while(left<right && a[left]<=flag) left++;
		swap(&a[left],&a[right]);
	}
	return left;//返回基准值的下标,以此为分界线,将区间划分成两个小区间 
}

void quickSort(int start,int end,int a[]){//递归调用(分治思想),直至所有的元素 
	if(start<end){
		int flag=partition(start,end,a);
		quickSort(start,flag-1,a);
		quickSort(flag+1,end,a);
	}
}

int main(){
	int a[10]={8,6,9,7,3,0,2,5,1,4};
	cout << "排序前的数组:" << endl;
	for(int i=0;i<10;i++){
		cout << a[i] << " ";
		if(i==9) cout << endl;
	}
	quickSort(0,9,a);
	cout << "排序后的数组:" << endl;
	for(int i=0;i<10;i++){
		cout << a[i] << " ";
		if(i==9) cout << endl;
	}
	return 0;
}
发布了10 篇原创文章 · 获赞 7 · 访问量 160

猜你喜欢

转载自blog.csdn.net/qq_44204959/article/details/104681475