1、冒泡排序
算法详解参考:https://mp.weixin.qq.com/s/wO11PDZSM5pQ0DfbQjKRQA
#include <iostream>
#include <vector>
using namespace std;
void swap(vector<int> &arr, int i, int j)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
void BubbleSort(vector<int> &arr)
{
int flag = 1; // flag标记是否继续比较元素大小,这里赋值为1是为了进入循环
for(int i = 1; i < arr.size() && flag; i++)
{
flag = 0; // 初始化为0
for(int j = arr.size() - 1; j >= i; j--)
{
if(arr[j] > arr[j+1]) // 升序
{
swap(arr, j+1, j);
flag = 1; // 不在比较元素时 flag = 1,进入下一次循环
}
}
}
}
int main()
{
vector<int> arr = {0, 5, 3, 4, 6, 2};
BubbleSort(arr);
for(int i = 0; i < arr.size(); i++)
cout << arr[i] << " ";
cout << endl;
return 0;
}
// 冒泡法排序总时间复杂度 O(n^2)
2、简单选择排序
算法详解参考:https://mp.weixin.qq.com/s/dGfh2t7xhg0wMM_DcYP1Cw
#include <iostream>
#include <vector>
using namespace std;
void swap(vector<int> &arr, int i, int j)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
void SelectSort(vector<int> &arr)
{
int min;
for(int i = 1; i < arr.size(); i++)
{
min = i;
for(int j = i+1; j <= arr.size(); j++)
{
if(arr[min] > arr[j])
min = j;
}
if(i != min)
swap(arr, i, min);
}
}
int main()
{
vector<int> arr = {0, 5, 3, 4, 6, 2};
SelectSort(arr);
for(int i = 0; i < arr.size(); i++)
cout << arr[i] << " ";
cout << endl;
return 0;
}
// 简单选择排序总时间复杂度 O(n^2)
// 性能略优于冒泡
3、直接插入排序
算法详解参考:https://mp.weixin.qq.com/s/McqFXkXucSZldjU46t5cdw
#include <iostream>
#include <vector>
using std::cout;
using std::endl;
using std::vector;
void swap(vector<int> &arr, int i, int j)
{
int a = arr[i];
arr[i] = arr[j];
arr[j] = a;
}
void InsertSort(vector<int> &arr)
{
for(int i = 1; i < arr.size(); i++)
{
int j = i;
while (j > 0 && arr[j] < arr[j-1])
{
swap(arr, j, j-1);
j--;
}
}
}
int main()
{
vector<int> arr = {0, 5, 3, 4, 6, 2};
InsertSort(arr);
for(int i = 0; i < arr.size(); i++)
cout << arr[i] << " ";
cout << endl;
return 0;
}
// 直接插入排序总时间复杂度 O(n^2)
// 性能优于冒泡和简单选择排序
4、希尔排序
算法详解参考:https://mp.weixin.qq.com/s/b9-dkpAhWJYshuSs5cwnOw
#include <iostream>
#include <vector>
using namespace std;
void ShellSort(vector<int> &arr)
{
int increment = arr.size(); // 希尔排序的增量初始化
while (increment > 1)
{
increment /= 2; // 增量折半
for(int i = 0; i < increment; i++)
{
for(int j = i+increment; j < arr.size(); j = j+increment)
{
int temp = arr[j];
int k = 0;
for(k = j-increment; k >= 0 && arr[k] > temp; k = k-increment)
arr[k + increment] = arr[k]; // 由于 k 的值发生了更新,但是在此循环结束之前索引 j 是没有发生变化的,所以 k + increment != j(第一次循环时 k+increment = j)
arr[k + increment] = temp;
}
}
}
}
int main()
{
vector<int> arr = {5, 8, 6, 3, 9, 2, 1, 7};
ShellSort(arr);
for(int i = 0; i < arr.size(); i++)
cout << arr[i] << " ";
cout << endl;
return 0;
}
// 希尔排序是不稳定排序
// Hibbard增量序列:最坏时间复杂度 O(n^(3/2))
// Sedgewick增量序列:最坏时间复杂度 O(n^(4/3))
5、堆排序
算法详解参考:https://mp.weixin.qq.com/s/8Bid1naBLtEjPoP-R4HkBg
#include <iostream>
#include <vector>
using namespace std;
// 大顶堆调整
void adjustHeap(vector<int> &arr, int i, int length)
{
int temp = arr[i]; // 先取出当前元素 i
for(int k = i*2 + 1; k < length; k = k*2 + 1) // 从 i 结点左子节点开始,也就是 2i+1 处开始
{
if(k+1 < length && arr[k] < arr[k+1]) // 如果左子节点小于右子节点,k指向右子节点
k++;
if(arr[k] > temp) // 如果子节点大于父节点,将子节点赋值给父节点(不用交换)
{
arr[i] = arr[k];
i = k;
}
else break;
}
arr[i] = temp; // 将 temp 值放到最终位置
}
// 元素交换
void swap(vector<int> &arr, int i, int j)
{
int a = arr[i];
arr[i] = arr[j];
arr[j] = a;
}
void heapSort(vector<int> &arr)
{
// 构建大顶堆
for(int i = arr.size()/2 - 1; i >= 0; i--)
// 从第一个非叶子结点从上至下,从右到左调整结构
adjustHeap(arr, i, arr.size());
// 调整堆结构加交换堆顶元素与末尾元素
for(int j = arr.size() - 1; j > 0; j--)
{
swap(arr, 0, j); // 将堆顶元素与末尾元素进行交换
adjustHeap(arr, 0, j); // 重新调整堆结构
}
}
int main()
{
vector<int> arr = {5, 8, 6, 3, 9, 2, 1, 7};
heapSort(arr);
for(int i = 0; i < arr.size(); i++)
cout << arr[i] << " ";
cout << endl;
return 0;
}
// 堆排序整体时间复杂度 O(nlogn)
6、归并排序
算法详解参考:https://mp.weixin.qq.com/s/885uGVhlffWAxjgIEW-TiA
#include <iostream>
#include <vector>
using namespace std;
void merge(vector<int> &arr, int start, int mid, int end)
{
// 开辟额外大集合,设置指针
vector<int> tempArray((end - start + 1), 0);
int p1 = start, p2 = mid+1, p = 0;
// 比较两个小集合的元素,依次放入大集合
while(p1 <= mid && p2 <= end)
{
if(arr[p1] <= arr[p2])
tempArray[p++] = arr[p1++];
else
tempArray[p++] = arr[p2++];
}
// 左(右)侧小集合有剩余,依次放入大集合尾部
while(p1 <= mid)
tempArray[p++] = arr[p1++];
while(p2 <= end)
tempArray[p++] = arr[p2++];
// 把大集合元素赋值回原数组
for(int i = 0; i < tempArray.size(); i++)
arr[i+start] = tempArray[i];
}
void mergeSort(vector<int> &arr, int start, int end)
{
if(start < end)
{
// 折半成两个小集合,分别进行递归
int mid = (start + end) / 2;
mergeSort(arr, start, mid);
mergeSort(arr, mid+1, end);
// 把两个有序小集合归并成一个大集合
merge(arr, start, mid, end);
}
}
int main()
{
vector<int> arr = {5, 8, 6, 3, 9, 2, 1, 7};
mergeSort(arr, 0, arr.size() - 1);
for(int i = 0; i < arr.size(); i++)
cout << arr[i] << " ";
cout << endl;
return 0;
}
// 总时间复杂度 O(nlogn)
7、快速排序
算法详解参考:https://zhuanlan.zhihu.com/p/93129029
// 快排递归实现
#include <iostream>
using namespace std;
void quickSort(int *arr, int begin, int end)
{
if(begin < end)
{
int temp = arr[begin];
int i = begin;
int j = end;
while(i < j)
{
while(i < j && arr[j] > temp)
j--;
arr[i] = arr[j];
while(i < j && arr[i] <= temp)
i++;
arr[j] = arr[i];
}
arr[i] = temp;
// 递归排序基准数两边子集
quickSort(arr, begin, i-1);
quickSort(arr, i+1, end);
}
else return;
}
int main()
{
int num[10] = {23, 14, 5, 7, 29, 50, 11, 33, 10, 8};
cout << "排序前: " << endl;
for(int i = 0; i < 10; i++)
cout << num[i] << " ";
cout << endl;
quickSort(num, 0, 9);
cout << "排序后: " << endl;
for(int i = 0; i < 10; i++)
cout << num[i] << " ";
cout << endl;
return 0;
}
// 快速排序时间复杂度 O(nlog2N)