下面算法编写的均是按照由小到大顺序进行排序版本
选择排序
思想:
每次遍历待排序元素的最大下标,与待排序元素中最后一个元素交换位置(此时需要设置一个临时变量来存放下标)
- 时间复杂度--O(n^2)
- 空间复杂度--O(1)
- 稳定性--不稳定
代码实现
#include<iostream>
using namespace std;
const int N = 1e2 + 10;
int num[N];
int n;void select_sort()
{for (int i = 1; i < n; i++)//控制找最大值的次数{int index = 1;//存待排序元素的最小元素的下标for (int j = 1; j <= n - i; j++){if (num[index] < num[j])index = j;}swap(num[index],num[n-i]);}
}
int main()
{cin >> n;for (int i = 1; i <= n; i++){cin >> num[i];}select_sort();for (int i = 1; i <= n; i++) cout << num[i] << " " << endl;
}
冒泡排序
思想:
相邻两个元素比较,前一个比后一个大则交换
(每遍历一次都会冒出最大值 每次遍历最后一个一定是最大的)
- 时间复杂度--O(n^2) (逆序时达到O(n^2))
- 空间复杂度O(--1)
- 稳定性--稳定
优化:
当整个数组遍历过程中没有发生交换,说明待排序数组已经有序,直接结束排序过程(bool类型变量做标记)
代码实现
#include <iostream>
using namespace std;
const int N = 1e2 + 10;
int num[N];
int n;void bubble_sort()
{for (int i = 1; i < n; i++){bool flag = false;for (int j = 1; j <= n - i; j++){if (num[j] > num[j + 1]){swap(num[j], num[j + 1]);flag = true;}}if (!flag) break;}
}int main()
{cin >> n;for (int i = 1; i <= n; i++){cin >> num[i];}bubble_sort();for (int i = 1; i <= n; i++){cout << num[i] << " ";}return 0;
}
计数排序(桶排序)
思想:
将数值作为桶号,遍历整个数组,将相应的桶进行计数
1、遍历原数组,找到最大值 max,然后申请max+1个空间(桶),初始化为0(下标为0-max),即vector<int>bucket(max+1,0)
2、再次遍历原数组,找到每个数值对应的桶号,并对桶计数++,即bucket[vec[i]++3、遍历桶数组,看对应的桶内计数为几就取出几下下标值(桶号),放到原数组中。
- 时间复杂度:O(n)
- 空间复杂度:O(n)
- 稳定性:稳定
代码实现
#include<iostream>
using namespace std;const int N = 1e4;
int num[N];
void Bucket_Sort(int n)
{//找待排序中的最大值int max = num[0];for (int i = 1; i < n; i++)max = max < num[i] ? num[i] : max;//创建桶int* bucket = new int[max + 1] {0};//将元素放入桶中for(int i=0;i<n;i++)bucket[num[i]]++;//计数//将元素取出还原int j = 0;for (int i = 1; i <= max; i++){while (bucket[i] > 0){num[j++] = i;bucket[i]--;}}
}
int main()
{int n;cin >> n;for (int i = 0; i < n; i++){cin >> num[i];}Bucket_Sort(n);for (int i = 0; i < n; i++){cout << num[i] << " ";}return 0;
}
插入排序
思想:
有序部分设置1个元素 无序部分设置n-1个元素,无序一个一个插入有序中。外层循环控制插入元素的个数(n-1) 内层找位置插入哪
- 时间复杂度 :O(n^2)
- 空间复杂度:O(1)
- 稳定性:稳定
代码实现
#include<iostream>
using namespace std;
void Insert_sort(int a[], int n)
{for (int i = 1; i < n; i++)//控制插入元素的个数{int temp = a[i];//记录插入元素int j = i - 1;//记录有序表中最后一个元素for (; j >= 0; j--){if (a[j] > temp)a[j + 1] = a[j];elsebreak;}a[j + 1] = temp;}
}int main()
{int a[6] = { 2,1,5,3,4,0 };Insert_sort(a, 6);for (int i = 0; i < 6; i++){cout << a[i] << " ";}return 0;
}
堆排序
思想:将待排序数组想象成一个最大堆结构,从最后一个有子节点的根节点开始调整,即最后一个父亲节点的下标(n/2-1),(若父亲节点的坐标为i,则其左孩子的下标是2i+1,右孩子下标是2i+2)
原理
1.完全二叉树:若树的深度为h,除第h层以外,其余各层(1~h-1)的节点数达到最大个数,第h层所有的节点都连续集中在最左边,只能从最深处右边从右往左缺省。
2.最大堆结构:是一个完全二叉树,堆中每个节点的值总是不大于其父亲节点的值(每颗子树上根节点最大,整棵树根节点最大)
3.创建最大堆结构:把所有非终端节点检查一遍,看是否满足最大堆的要求,若不满足,则进行调整(检查当前节点是否满足:根>=左、右,若有不满足,则当前节点与更大的一个人孩子节点进行交换,若元素互换破坏了下一级的堆,则采用相同的方式继续调整,直至符合最大堆要求,我们以数组{53,27,78,9,45,65,87,32}为例.
(二叉树的终端节点:度为零的节点,就是叶子节点)
- 时间复杂度:O(nlog2 n)
- 空间复杂度:O(1)
- 稳定性:不稳定
#include<iostream>
#include<vector>
#include<cmath>
using namespace std;void adjustHeap(vector<int>& vec, int start, int end)
{int father = start;//根节点int child = father * 2 + 1;//左子树while (child <= end)//循环是为了再调整最大堆的过程中破坏子树的结结构,继续向下调整 {//因为child是左子树,根节点要大于左右子树,所以要在子树中找到最大的再与根节点进行比较,//所以要防止右子树越界就是在数组下标为child+1的元素,child就是子树中最大的元素 if (child + 1 <= end && vec[child + 1] > vec[child])child++;if (vec[child] > vec[father])//如果根节点小于子树就交换 {swap(vec[child], vec[father]);//如果发生交换继续向下调整,因为可能破环子树的最大堆结构father = child;child = 2 * father + 1;}//如果没有发生交换就退出该函数elsereturn;}
}
void HeapSort(vector<int>& vec)
{//从最后一个有子节点的节点开始调整//O(n)for (int i = vec.size() / 2 - 1; i >= 0; i--)//vec.size()/2是完全二叉树最后一个有子节点的节点 {adjustHeap(vec, i, vec.size() - 1);}//O(nlog2 n)for (int i = vec.size() - 1; i >= 1; i--){swap(vec[0], vec[i]);//只有下表为为0的元素被打乱,从根节点开始向下调整adjustHeap(vec, 0, i - 1);}
}
int main()
{vector<int>vec = { 53,17,78,9,45,65,87,32 };HeapSort(vec);for (auto it : vec){cout << it << " ";}return 0;
}
如果你对探索机器学习的无限可能性、掌握Python编程的技巧、以及玩转各种框架的技能充满了好奇心,那么恭喜你,你来对地方了!赶紧扫描下方二维码,加入我们的微信公众号吧!这里有最新的技术趋势、独家教程、精彩案例等着你,让我们一起探索未知的领域,开启编程之旅吧!🚀🌟