作者:求一个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)。
标签:int,res,复杂度,通俗易懂,++,C++,数组,校招,排序 From: https://blog.csdn.net/qq_60018273/article/details/139863614