下面算法编写的均是按照由小到大顺序进行排序版本
选择排序
思想:
每次遍历待排序元素的最大下标,与待排序元素中最后一个元素交换位置(此时需要设置一个临时变量来存放下标)
- 时间复杂度--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];
else
break;
}
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;
}
//如果没有发生交换就退出该函数
else
return;
}
}
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编程的技巧、以及玩转各种框架的技能充满了好奇心,那么恭喜你,你来对地方了!赶紧扫描下方二维码,加入我们的微信公众号吧!这里有最新的技术趋势、独家教程、精彩案例等着你,让我们一起探索未知的领域,开启编程之旅吧!🚀🌟