校招常见七大排序C++版(适合新人,通俗易懂)

作者:求一个demo

版权声明:著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处

内容通俗易懂,没有废话,文章最后是面试常问内容

是否稳定最优、最坏、平均时间复杂度最优、最坏、平均空间复杂度
冒泡排序O(n)、O(n^2)、O(n^2)0、O(n)、O(1)
选择排序O(n^2)、O(n^2)、O(n^2)O(1)、O(1)、O(1)
插入排序O(n)、O(n^2)、O(n^2)O(1)、O(1)、O(1)
桶排序O(n)、O(n^2)、O(n)O(n)、O(n)、O(n)
堆排序O(nlogn)、O(nlogn)、O(nlogn)O(1)、O(1)、O(1)
快速排序O(nlogn)、O(n^2)、O(nlogn)O(logn)、O(n)、O(logn)
归并排序O(nlogn)、O(nlogn)、O(nlogn)O(n)、O(n)、O(n)

 

 

一、冒泡排序

描述:相邻两个进行比较,一轮遍历之后,把最大值放到了最后,接着一直循环查找

1、代码样例

#include <iostream>
#include <vector>

using namespace std;

void selectSort(vector<int>&res,int n) {
	for (int i = n; i > 0;i--) {
		bool ret = true;
		for (int j = 0; j < i - 1;j++) {
			if (res[j]>res[j+1]) {
				swap(res[j],res[j+1]);
				ret = false;
			}
		}
		if (ret == true) {
			return;
		}
	}
}

void selectPrint(vector<int>&res) {
	for (int i = 0; i < res.size();i++) {
		cout << res[i] << " " ;
	}
	cout << endl;
}

int main() {
	vector<int>res = {4,2,5,3,1};
	selectSort(res,res.size());
	selectPrint(res);
	return 0;
}

2、复杂度分析 

首先,讲述一下时间复杂度和空间复杂度区别

①时间复杂度主要是看算法的执行时间,也就是算法处理数据所需的时间是多少。例如for循环里面嵌套一个for循环,两个for循环都是循环n次,那么时间复杂度就是n*n,也就是O( n^2 );O(1)表示时间复杂度是常数,是最理想的。

②空间复杂度主要是看算法在执行过程中占用了多少的存储空间,也就是算法所需要的空间资源。例如O(1)表示算法的空间复杂度不随问题规模的变化而变化,即占用固定大小存储空间;O(n)或O(n^2)表示算法的空间复杂度与问题的规模成正比,只是增长幅度不同。

(1)时间复杂度

最优时间复杂度:O( n ),即待排序的元素已经完全有序时,一次遍历即可完成排序。

最坏时间复杂度:O( n^2 ),即待排序的元素逆序排序时。

平均时间复杂度:O( n^2 ),即待排序元素正常乱序的话一般是两个嵌套的for循环进行查找。

(2)空间复杂度

最优空间复杂度:0,即待排序元素已经排好序了,不需要排序了。

最坏空间复杂度:O(n),即待排序元素逆序排序。

平均空间复杂度:O(1),即平均下来该算法占用某固定大小的存储空间。

二、选择排序

描述: 数组中从头遍历一遍,找到最大值之后,和数组最后一个值交换位置,然后继续寻找。遍历第二遍,找到除数组最后一个位置的最大值之外的最大值,然后和数组倒数第二个位置交换。依次这样进行,将数组进行从小到大排序。

1、代码样例

#include <iostream>
#include <vector>

using namespace std;

void selectSort(vector<int>&res,int n) {
	//i代表待排序数组的个数,下标为0到i-1
	for (int i = n; i > 1; i--) {
		//第一步:找到最大值,并记录它的下标
		int max = res[0];
		int maxindex = 0;
		for (int j = 1; j < i;j++) {
			if (max < res[j]) {
				max = res[j];
				maxindex = j;
			}
		}
		//最大的数放在最后面
		swap(res[maxindex],res[i-1]);
	}
}

void selectPrint(vector<int>&res) {
	for (int i = 0; i < res.size();i++) {
		cout << res[i] << " " ;
	}
	cout << endl;
}

int main() {
	vector<int>res = {4,2,5,3,1};
	selectSort(res,res.size());
	selectPrint(res);
	return 0;
}

2、复杂度分析

(1)时间复杂度

最优时间复杂度:O( n^2 ),即待排序的元素已经完全有序,仍需两个for循环(第一个for循环表示待排序元素个数,第二个for循环找到最大值并记录下标)

最坏时间复杂度:O( n^2 ),即待排序的元素逆序排序时,仍需两个for循环。

平均时间复杂度:O( n^2 ),即待排序元素正常乱序的话,需要两个for循环。

(2)空间复杂度

最优空间复杂度:O(1)。

最坏空间复杂度:O(1)。

平均空间复杂度:O(1)。

三、插入排序

描述:分为有序区和无序区。有序区起初默认为一个元素,无序区元素和有序区最后一个元素比较,如果小于有序区最后一个元素,再和有序区倒数第二个元素比较,以此类推,最后插入到合适的位置。

1、代码样例

#include <iostream>
#include <vector>

using namespace std;

void selectSort(vector<int>&res,int n) {
	for (int j = 1; j < n;j++) {
		int i = j - 1;
		while (i>=0 && res[i]>res[i+1]) {
			swap(res[i],res[i+1]);
			i--;
		}
	}
}

void selectPrint(vector<int>&res) {
	for (int i = 0; i < res.size();i++) {
		cout << res[i] << " " ;
	}
	cout << endl;
}

int main() {
	vector<int>res = {4,2,5,3,1};
	selectSort(res,res.size());
	selectPrint(res);
	return 0;
}

2、复杂度分析

(1)时间复杂度

最优时间复杂度:O( n ),即待排序的元素已经完全有序时,插入排序只需每次比较一次就可确定当前元素位置。

最坏时间复杂度:O( n^2 ),即待排序的元素逆序排序时,每次插入都需将当前元素逐个与已排序元素进行比较。

平均时间复杂度:O( n^2 ),即待排序元素正常乱序的话,每个元素比较和移动的次数都接近1/2。

(2)空间复杂度

最优空间复杂度:O(1)。

最坏空间复杂度:O(1)。

平均空间复杂度:O(1)。

 四、桶排序

描述(此算法思路以下面四步为例):

第一步:找到数组a中最大值max。

第二步:申请一个数组b(桶),大小为max+1,即下标为0到max。

第三步:把数组a中元素值与数组b下标对应,并使数组b下标对应的值进行++。

第四步:最后遍历数组b,从小到大存入数组a,进行输出。

1、代码样例

#include <iostream>
#include <vector>

using namespace std;

void selectSort(vector<int>&res) {
	if (res.size() == 0) {
		return;
	}
	int max = res[0];//max用来存放数组最大值
	for (int i = 1; i < res.size();i++) {//找到数组最大值,方便申请桶大小
		if (res[i]>max) {
			max = res[i];
		}
	}
	vector<int>max_res(max+1,0);
	for (int i = 0; i < res.size();i++) {//数组中值存到桶里
		max_res[res[i]]++;
	}
	int index = 0;
	for (int i = 0; i < max_res.size();i++) {
		while (max_res[i]) {
			res[index++] = i;
			max_res[i]--;
		}
	}
}

void selectPrint(vector<int>&res) {
	for (int i = 0; i < res.size();i++) {
		cout << res[i] << " " ;
	}
	cout << endl;
}

int main() {
	vector<int>res = {4,2,5,3,1};
	selectSort(res);
	selectPrint(res);
	return 0;
}

2、复杂度分析 

(1)时间复杂度

最优时间复杂度:O( n ),即待排序元素分布均匀时(k为桶的个数)。

最坏时间复杂度:O( n^2 ),即所有待排序元素都在一个桶中。

平均时间复杂度:O( n)。

(2)空间复杂度

最优空间复杂度:O(n),需要额外空间来存储桶和桶内元素。

最坏空间复杂度:O(n)。

平均空间复杂度:O(n)。

五、堆排序

描述:

1、代码样例

#include <iostream>
#include <vector>

using namespace std;

void adjustHeap(vector<int>&res,int start,int end) {
	int father = start;
	int leftChild = start * 2 + 1;
	int rightChild = leftChild + 1;
	int maxChild = leftChild;//记录最大孩子的下标
	while (leftChild < end) {
		if (rightChild<end && res[leftChild]<res[rightChild]) {
			maxChild = rightChild;
		}
		if (res[maxChild]>res[father]) {
			swap(res[maxChild] , res[father]);
		}
		else {
			return;
		}
		father = maxChild;
		leftChild = father * 2 + 1;
		rightChild = leftChild + 1;
		maxChild = leftChild;
	}
}

void heapSort(vector<int>&res) {
	//创建最大堆
	for (int i = res.size() / 2 - 1; i >= 0;i--) {
		adjustHeap(res,i,res.size());
	}
	//一开始是0到n-1这个范围找最大值
	int end = res.size() - 1;
	//交换数据
	while (end>=1) {
		swap(res[0],res[end]);
		adjustHeap(res,0,end--);
	}
}

void Print(vector<int>&res) {
	for (int i = 0; i < res.size();i++) {
		cout << res[i] << " " ;
	}
	cout << endl;
}

int main() {
	vector<int>res = {4,2,5,3,1};
	heapSort(res);
	Print(res);
	return 0;
}

2、复杂度分析 

(1)时间复杂度

最优时间复杂度:O( nlogn ),即需要进行堆的建立和调整,建立大小为n的堆时间复杂度为O(n),因为确保节点值大于或小于子节点的值(对最大堆和最小堆而言),建堆的过程每个节点复杂度为O(logn),每次从堆顶取出最大(或最小)元素与堆中最后一个元素交换,然后对剩下n-1个元素进行堆调整,每次调整堆的时间复杂度为Q(logn)。

最坏时间复杂度:O( nlogn )。

平均时间复杂度:O( nlogn)。

(2)空间复杂度

最优空间复杂度:O(1),即堆排序不需要额外申请空间,只在原数组上进行原地调整。

最坏空间复杂度:O(1)。

平均空间复杂度:O(1)。

六、快速排序

1、三色旗思想

介绍快速排序之前,先介绍三色旗思想(快排以三色旗思想为基础,原理相同)

三色旗描述:三色旗问题:数组内值和1进行对比,如果是2就和最后元素交换,如果是1 下标++但不交换,如果是0就和最前面交换。

(1)代码样例
#include <iostream>
#include <vector>

using namespace std;

//中有0,1,2(三色旗问题)三种值的数组,进行排序
void Quick(vector<int>&res,int L,int R) {
	int left = L - 1;
	int right = R + 1;
	int index = 0;
	int temp = 1;
	while (index < right) {
		if (res[index]==temp) {//说明是1
			index++;
		}
		else if (res[index] < temp) {//说明是0
			swap(res[index++],res[++left]);
		}
		else {//说明是2
			swap(res[index],res[--right]);
		}
	}
}

int main() {
	vector<int>res = {0,1,2,0,2,1,0,1};
	Quick(res,0,res.size()-1);
	for (auto it :res) {
		cout << "res: " << it << endl;
	}
	return 0;
}

2、快速排序

描述:快速排序的思想是将数组分成前后两组,分别进行排序(借助三色旗排序的思想),然后将两个数组进行合并即可

(1)代码样例
#include<iostream>
#include<vector>
using namespace std;

pair<int, int> Quick(vector<int>& vec, int L, int R) {
	int temp = vec[L];
	int i = L - 1;
	int j = R + 1;
	int index = L;
	while (index < j) {
		if (vec[index] > temp) {
			swap(vec[index], vec[--j]);
		}
		else if (vec[index] < temp) {
			swap(vec[index++], vec[++i]);
		}
		else
			index++;
	}
	return make_pair(i, j);
}

void Quick_sort(vector<int>& vec, int L, int R) {
	if (L >= R) return;
	pair<int, int> p = Quick(vec, L, R); // 三色旗思想
	Quick_sort(vec, L, p.first); // 对第一部分进行三色旗
	Quick_sort(vec, p.second, R); // 对第二部分进行三色旗
}

int main() {
	vector<int> vec = { 2, 4, 3, 1, 7, 6, 5, 9 };
	Quick_sort(vec, 0, vec.size() - 1);
	for (auto it : vec) {
		cout << it << " ";
	}
	return 0;
}

2、复杂度分析 

(1)时间复杂度

最优时间复杂度:O( nlogn),即每次划分时间复杂度为O(n),总共需要O(logn)次划分。

最坏时间复杂度:O( n^2),即每次划分只能将数组分为一个元素和其余元素两个部分。

平均时间复杂度:O( nlogn)。

(2)空间复杂度

最优空间复杂度:O(logn)。

最坏空间复杂度:O(n)。

平均空间复杂度:O(logn)。

七、归并排序

描述:将两个有序数组合并成一个有序数组。

第一步:将数组进行分解,当分解成单个元素为一组的时候才是组内有序的。

第二步:将两两有序的数组进行合并,将两个有序数组合并成一个有序数组。重复第二步,直至排序完成。
合并的步骤:先申请两数组合并后那么大小的空间,然后将两个排好序的数组逐一进行比较,往申请空间里面放。

1、代码样例

#include<iostream>
#include<vector>
using namespace std;

void Merg(vector<int>&res,int L,int mid,int R) {
	vector<int>temp(R-L+1);//临时数组,用来存放这次排序完的数组,然后再放入res中
	int i = L;
	int j = mid+1;
	int index = 0;
	while(i<=mid && j<=R) {
		if (res[i]<res[j]) {
			temp[index++] = res[i++];
		}
		else{
			temp[index++] = res[j++];
		}
	}
	//此时两边存在剩余情况
	while (i <= mid) {
		temp[index++] = res[i++];
	}
	while (j <= R) {
		temp[index++] = res[j++];
	}
	index = L;
	for (int i = 0; i < (R - L + 1); i++) {
		res[index++] = temp[i];
	}
}

void Merg_Sort(vector<int>&res,int L,int R) {
	if (L >= R) {
		return;
	}
	int mid = (R - L) / 2 + L;
	Merg_Sort(res,L,mid);
	Merg_Sort(res,mid+1,R);
	Merg(res,L,mid,R);
}

int main() {
	vector<int> vec = { 2, 4, 3, 1, 7, 6, 5, 9 };
	Merg_Sort(vec,0,vec.size()-1);
	for (auto it : vec) {
		cout << it << " ";
	}
	return 0;
}

2、复杂度分析 

(1)时间复杂度

最优时间复杂度:O( nlogn),即每次合并复杂度为O(n),递归深度为O(logn)。

最坏时间复杂度:O( nlogn)。

平均时间复杂度:O( nlogn)。

(2)空间复杂度

最优空间复杂度:O(n)。

最坏空间复杂度:O(n)。

平均空间复杂度:O(n)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值