#include <iostream>
#include <algorithm>
#include <vector>
#include <string>
using namespace std;
/*
稳定:如果原本序列中a在b前面且a=b,排序后a仍在b前面,顺序不变;
不稳定:如果原本序列中a在b前面且a=b,排序后a可能在b后面,顺序可能发生改变;
内排序:所有排序操作均在内存中完成;
外排序:由于数据量太大,将其放入磁盘中,排序过程中需要磁盘与内存之间的数据传输;
时间复杂度:一个排序算法在执行过程中所耗费的时间量级的度量;
空间复杂度:一个排序算法在运行过程中临时占用存储空间大小的度量
*/
//------------------------------------------------------分割线----------------------------------------------------//
//1、冒泡排序
void BubbleSort(int data[], int n) {
int flag = 0;
for (int i = 0; i < n; i++) {
flag = 0;
for (int j = 1; j < n; j++) {
if (data[j] < data[j - 1]) {
flag = 1;
int t = data[j];
data[j] = data[j - 1];
data[j - 1] = t;
}
}
if (flag == 0)return;
}
}
//------------------------------------------------------分割线----------------------------------------------------//
//2、选择排序
//选择最大值的下标,然后交换
int findMax(int data[], int n) {
int max = data[0];
int pos = 0;
for (int i = 1; i < n; i++) {
if (data[i] > max) {
max = data[i];
pos = i;
}
}
return pos;
}
void SelectSort(int data[], int n) {
while (n > 1) {
int pos = findMax(data, n);
int tmp = data[n - 1];
data[n - 1] = data[pos];
data[pos] = tmp;
n--;
}
return;
}
//------------------------------------------------------分割线----------------------------------------------------//
//3、插入排序
//对前2个,前3个,前n个以此插入排序
void InsertSort(int data[], int n) {
int j;
for (int i = 1; i < n; i++) {
int key = data[i];
for ( j= i; j > 0; j--) {
if (j-1>=0 && data[j-1] > key) {
data[j] = data[j - 1];
}
else break;
}
data[j] = key;
}
}
void InsertSort2(int data[], int n) {
int j;
for (int i = 1; i < n; i++) {
j = i;
int tmp = data[i];
while (j > 0) {
if (tmp < data[j - 1]) {
swap(data[j], data[j - 1]);
//data[j] = data[j-1];
j--;
}
else break;
}
//data[j] = tmp;
}
}
//------------------------------------------------------分割线----------------------------------------------------//
//4、希尔排序
//确定一个步长,将数组变成部分有序,每一趟都采用插入排序
void ShellSort(int arr[], int n)
{
int i, j, inc, key;
//初始增量:n/2,每一趟之后除以2
for (inc = n / 2; inc > 0; inc /= 2) {
//每一趟采用插入排序
for (int i = inc; i < n; i++) {
key = arr[i];
//每一组采用插入排序
for (j = i; j >= inc && key < arr[j - inc]; j -= inc) {
arr[j] = arr[j - inc];
}
arr[j] = key;
}
}
}
//------------------------------------------------------分割线----------------------------------------------------//
//5、堆排序
/*
维护堆的性质:堆为完全二叉树,大顶堆指父节点的值大于子节点,小顶堆反之
n : 数组长度
i : 待维护节点的下标
下标为i的节点的父节点下标: (i-1)/2
下标为i的节点的左孩子下标: i*2+1
下标为i的节点的右孩子下标: i*2+2
*/
//维护大顶堆
void headify(int arr[], int n, int i) {
int largest = i;
int lson = i * 2 + 1;
int rson = i * 2 + 2;
if (lson < n && arr[largest] < arr[lson]) {
largest = lson;
}
if (rson < n&&arr[largest] < arr[rson]) {
largest = rson;
}
if (largest != i) {
swap(arr[largest], arr[i]);
headify(arr, n, largest);
}
}
//堆排序入口
void headSort(int arr[], int n) {
//建堆
for (int i = n / 2 - 1; i >= 0; i--) {
headify(arr, n, i);
}
//排序
for (int i = n - 1; i > 0; i--) {
swap(arr[i], arr[0]);
headify(arr, i, 0);
}
}
//------------------------------------------------------分割线----------------------------------------------------//
//6、快速排序
//分治、双指针思想
//划分:选取最右边的值为基准
int partition(int arr[], int low, int high) {
int pivot = arr[high];
int i = low;
for (int j = low; j < high; j++) {
//比pibot小的,全部换到前面去
if (arr[j] < pivot) {
swap(arr[j], arr[i++]);
}
}
//此时,i指向的元素一定大于等于pivot
swap(arr[high], arr[i]);
return i;
}
void qsort(int arr[], int low, int high) {
if (low < high) {
int mid = partition(arr, low, high);
qsort(arr, low, mid - 1);
qsort(arr, mid + 1, high);
}
}
void quickSort(int arr[], int n) {
qsort(arr, 0, n - 1);
}
//------------------------------------------------------分割线----------------------------------------------------//
//7、计数排序
void countSort(int arr[], int n) {
if (n < 1)return;
//寻找最大的元素
int max = arr[0];
for (int i = 0; i < n; i++) {
if (arr[i] > max)max = arr[i];
}
//分配一个长度为max+1的数组存储计数,并初始化为0
vector<int>count(max + 1, 0);
//计数
for (int i = 0; i < n; i++) {
count[arr[i]]++;
}
//统计计数的累加值
for (int i = 1; i < max + 1; i++) {
count[i] += count[i - 1];
}
//创建一个临时数组保存结果
int* tmp = (int*)malloc(n * sizeof(int));
for (int i = 0; i < n; i++) {
tmp[count[arr[i]]-1] = arr[i];
count[arr[i]]--;
}
for (int i = 0; i < n; i++) {
arr[i] = tmp[i];
}
}
//------------------------------------------------------分割线----------------------------------------------------//
//8、归并排序
void merge(int arr[], int tmpArr[], int left, int mid ,int right){
//标记左半区第一个未排序的元素
int l_pos = left;
//标记右半区第一个未排序的元素
int r_pos = mid + 1;
//临时数组元素的下标
int pos = left;
//合并
while (l_pos <= mid && r_pos <= right) {
if (arr[l_pos] < arr[r_pos]) {
tmpArr[pos++] = arr[l_pos++];
}
else tmpArr[pos++] = arr[r_pos++];
}
//合并左半区剩余的元素
while (l_pos <= mid) {
tmpArr[pos++] = arr[l_pos++];
}
//合并右半区剩余的元素
while (r_pos <= right) {
tmpArr[pos++] = arr[r_pos++];
}
while (left <= right) {
arr[left] = tmpArr[left];
left++;
}
}
//递归切分
void msort(int arr[], int tmpArr[], int left, int right) {
//如果只有一个元素,那么就不需要划分
if (left == right)return;
if (left < right) {
//找中间点
int mid = left+(right-left)/2;
msort(arr, tmpArr, left, mid);
msort(arr, tmpArr, mid + 1, right);
//合并已经排序的部分
merge(arr, tmpArr, left, mid, right);
}
}
//归并排序入口
void mergeSort(int arr[], int n) {
//分配一个辅助数组
//C风格:
int* tmpArr = (int*)malloc(n * sizeof(int));
if (tmpArr) {
msort(arr, tmpArr, 0, n - 1);
free(tmpArr);
}
else {
printf("error: failed to allocate memory");
}
}
int main() {
int a[10] = { 3,2,4,1,5 ,10,8,6,7,9};
//1、冒泡排序,时间复杂度最小O(n),最大为O(n^2),空间复杂度O(1)
//BubbleSort(a, 5);
//2、选择排序,平均时间复杂度为O(n^2),空间复杂度O(1),不稳定
//SelectSort(a, 5);
//3、插入排序,时间复杂度最小O(n),最大为O(n^2),空间复杂度O(1),稳定
//InsertSort2(a, 10);
//4、希尔排序,时间复杂度与选取的分组长度序列有很大关系,最好为O(n*log^2(n)),最小为O(n^2)
//平均复杂度为O(n^3/2),空间复杂度为O(1),不稳定
//ShellSort(a, 5);
//5、堆排序,时间复杂度为O(n*logn),建堆复杂度为O(n),heapify复杂度为O(logn),空间复杂度为
//O(1),不稳定
headSort(a, 10);
//6、快速排序,时间复杂度最小为O(n*logn),最大为O(n^2),平均为O(n*logn),空间复杂度为
//O(logn),不稳定
//quickSort(a, 5);
//7、计数排序,时间复杂度为O(n+k) ,即n个0~k之间的数,空间复杂度为O(k),稳定
//适用于对最大值不是很大的整型元素序列进行排序的情况
//countSort(a, 5);
//8、归并排序,时间复杂度为O(n*logn),每一层归并的时间复杂度为O(n),归并层数最大为O(logn + 1)
//空间复杂度为O(n),稳定
//mergeSort(a, 5);
for (int i = 0; i < 10; i++) {
cout << a[i] << " ";
}
return 0;
}
八大排序算法-C++实现
最新推荐文章于 2024-08-13 22:08:16 发布