参考博文:各种排序-从这篇文章中记录了学习笔记(搬运过来),掌握了原理,代码一定要结合图解手撸一遍。
1.1 算法思想
1.3 代码
//冒泡排序
void bubbleSort(int* arr, int len)
{
for (int i = 0; i < len - 1; i++) //表示要找到len-1个最大数
{
for (int j = 0; j < len - 1 - i; j++) //每次最大数都遍历一遍,找到最大值
{
if (arr[j] > arr[j + 1])
swap(arr[j], arr[j + 1]);
}
}
}
2.1 算法思想
最小(大)元素
,存放到排序序列的起始位置
。未排序
元素中继续寻找最小(大)元素
,然后放到自己已排序
的序列的末尾。时间复杂度O(n^2)
//选择排序(升序)
void selectionSort(int* arr,int len)
{
//从第一个位置找,共找len-1个最小数
for (int i = 0; i < len - 1; i++)
{
int min = i;//min为最小值位置 初始认为i处是最小
//接下来找到最小数放到第i个位置
for (int j = i + 1; j < len; j++)
{
if (arr[j] < arr[min])
min = j; //如果找到更小的,就记录当前位置
}
swap(arr[i], arr[min]); //最后将未排序中找到的最小值和第i个位置交换
}
}
3.1 算法思想
将无序元素
插到有序元素
中去
时间复杂度O(n^2),不稳定,
3.3 代码
//插入排序(升序)
void insertSort(int* arr,int len)
{
//第1个位置已叫排序,从第2个位置到最后一个位置插入len-1次
for (int i = 1; i < len; i++)
{
//第i个位置装配,开始找插入位置
int temp = arr[i];
int j = i - 1;
while (j >= 0 && temp < arr[j])//条件分两种情况:1、插入中间 2、插入头部
{
arr[j + 1] = arr[j];
j--;
}
//j位置的值比temp小,就插入j+1位置
arr[j + 1] = temp;
}
}
4.1 算法思想
4.3 代码
//快速排序(升序) 使用了递归方法,递归函数详细描述一层运算
void quickSort(int* arr,int left,int right)
{
//设置迭代截至条件
if (left >= right) return;
//两个标志承接左右下标 设置初始基准值
int begin = left;
int end = right;
int key = arr[end];
//开始当前一层的运算
while (begin < end)
{
//基准左边一般为小 找大
while (begin < end && arr[begin] <= key) begin++;
arr[end] = arr[begin];//如果找到大的,将其提取到右边end处
//基准右边一般为大 找小
while (begin < end && arr[end] >= key) end--;
arr[begin] = arr[end];//如果找到小的,将其提取到左边begin处
}
arr[end] = key;//最后将基准放在begin和end交界处
//开启下一层运算
quickSort(arr, left, end - 1);//基准左边排序交给迭代函数
quickSort(arr, end + 1, right);//基准右边排序交给迭代函数
}
5.1 算法思想
参考博文:堆排序(C语言)
定义了以下几种操作:
(1)最大堆调整(Heapify):将堆的末端子节点作调整,使得子节点永远小于父节点
(2)创建最大堆(CreateHeap):将堆中的所有数据重新排序
(3)堆排序(HeapSort):移除位在第一个数据的根节点,并做最大堆调整的递归运算
堆
是一个近似完全二叉树的结构
数组a[k]与二叉树的性质:
父节点:(k-1)/2
左子节点:2k+1
右子节点:2k+2
5.3 代码
//堆排序
//子函数:最大对调整 迭代 (前提是其子节点已经成为最大堆,检验这个父节点有没有实力,没有则为其安排在适合的位置,谁有能力谁上)
void heapify(int* arr,int len,int k)
{
//迭代继续条件 检验父节点
if (k < len)
{
int max = k; //假设父节点最大
int s1 = 2 * k + 1; //子节点索引
int s2 = 2 * k + 2; //子节点索引
//看看子节点有没有更强的
if (s1<len && arr[s1]>arr[max]) max = s1;
if (s2<len && arr[s2]>arr[max]) max = s2;
//如果有强的,子节点上,父节点继续和下边儿比较
if (max != k)
{
swap(arr[max], arr[k]);
heapify(arr, len, max);//退下来的父节点继续看看这个位置他能把握住吗
}
}
}
//堆排序函数
void heapSort(int* arr, int len)
{
//1、创建最大堆 根节点为最大数
int last_node = len - 1;
int last_parent = (last_node - 1) / 2;//最后一个父节点
//从低向上 创建最大堆 每一小步都是用最大堆调整
for (int i = last_parent; i >= 0; i--)
heapify(arr, len, i);
//2、每次根节点为最大数 放后边儿 升序排序
for (int i = len - 1; i >= 0; i--)
{
swap(arr[0], arr[i]);
heapify(arr, i, 0);//这里剩余数量正好是i 对新的根节点重新调整审视(因为已经创建后的最大堆,除了根节点,其他都符合最大堆性质)
}
}
6.1 算法思想
将数组元素分成若干组,每组分别进行插入排序
,使整个数组逐渐变成部分有序数组,再慢慢减少所分的组数,最终合并成一个组 。
将数组多次分组,分别进行插入排序—改进的插入排序。
参考博文:排序算法之希尔排序、希尔排序C++实现
6.3 代码
//希尔排序
void shellSort(int* arr,int len)
{
int group = len / 2;//分组数
//不同组数下,对每组插入排序
while (group >= 1)
{
//希尔排序下的插入排序
//外层循环 确定要选哪些点插入
for (int i = group; i < len; i++)
{
int temp = arr[i];//要插入的值存入临时变量
int j = i - group;//插入已排好序的数组用到的指针
//内层循环 插入
while (j>=0&&temp<=arr[j])
{
arr[j + group] = arr[j];//正常都是慢慢排查
j = j - group;
}
arr[j + group] = temp;//找到位置了 插入
}
group /= 2;//该换小点儿的分组了
}
}
7.1 算法思想
最大
和最小
的元素i∈[min:1:max]
的元素出现的个数,存入数组c的第i-min项原数组
中。本算法图解更容易理解
7.3 代码
时间复杂度:O(n+k),n容量的原数组,k容量的计数数组,实际分别遍历了两个数组,所有好坏情况都是O(n+k)。
空间复杂度:O(k),新建了k容量的计数数组。
//计数排序
void countSort(int* arr, int len)
{
//1、找最大最小值
int min = arr[0];
int max = arr[0];
for (int i = 0; i < len; i++)
{
if (arr[i] < min) min = arr[i];
if (arr[i] > max) max = arr[i];
}
//2、创建计数数组
int len_count = max - min + 1;//计数数组长度
int* arr_count = new int[len_count];
for (int i_count = 0; i_count < len_count; i_count++)
arr_count[i_count] = 0;
for (int i = 0; i < len; i++)//核心,为每个数计数
{
arr_count[arr[i] - min] += 1;
}
//3、计数数组-按顺序放回->原数组
int i_total = 0;
for (int i_count = 0; i_count < len_count; i_count++)
{
for (int i_temp = 0; i_temp < arr_count[i_count]; i_temp++)
{
arr[i_total++] = min + i_count;//装入真实的数
}
}
}
8.1 算法思想
位数
。0~9的桶
里进行计数排序);参考博文:C++排序算法之基数排序
8.3 代码
//基数排序
//获得数组中最大数的位数
int maxBit(int* arr, int len)
{
int bit_num = 0;
for (int i = 0; i < arr[i]; i++)//遍历数组
{
//获取当前数的位数
int temp = arr[i];
int bit_temp = 0;
while (temp > 0)
{
temp /= 10;
bit_temp++;
}
//比较是否是最大位数
if (bit_temp > bit_num)
bit_num = bit_temp;
}
return bit_num;
}
//基数排序的简单实现
void radixSort(int* arr, int len)
{
int bit_max = maxBit(arr, len); //获得数组中最大数的位数
vector<vector<int>> buckets(10); //新建10个桶
int r = 1; //作为除数
for (int i_bit = 0; i_bit < bit_max; i_bit++)//从低位向高位遍历
{
//1、遍历数组,将数放桶里
for (int i = 0; i < len; i++)
{
int num_temp = (arr[i] / r) % 10;//取特定的那一位
buckets[num_temp].push_back(arr[i]);
}
//2、遍历桶,按桶的顺序放回数组
int i_origin = 0;
for (int i_bucket = 0; i_bucket < 10; i_bucket++)
{
if (!buckets[i_bucket].size()) continue;
for (vector<int>::iterator itr_num = buckets[i_bucket].begin(); itr_num != buckets[i_bucket].end(); itr_num++)
{
arr[i_origin++] = *itr_num;
}
buckets[i_bucket].clear();//用完顺便清空,以便下次再用。
}
r *= 10;
}
}
9.1 算法思想
是计数排序的进化版
空桶子
。放到对应的桶子
去(将数组分段划分、按位数划分等)。排序
(其他适合小范围的排序,如插入排序)。参考博文:C/C++桶排序
9.3 代码
//桶排序
void bucketSort(int* arr, int len)
{
//寻找最大最小值
int min_value = arr[0];
int max_value = arr[0];
for (int i = 1; i < len; i++)
{
if (arr[i] < min_value) min_value = arr[i];
if (arr[i] > max_value) max_value = arr[i];
}
//初始化桶,将数组的数据按某一分组装入桶中
int bucketsize = 5; //桶大小
int buckets_num = (max_value - min_value) / bucketsize + 1; //桶数量
vector<vector<int>> buckets(buckets_num);
for (int i = 0; i < len; i++)
{
int index = (arr[i] - min_value) / bucketsize;
buckets[index].push_back(arr[i]);
}
//对每个桶排序,装回原数组
int i_origin = 0; //全程记录原数组索引
for (int i_bucket = 0; i_bucket < buckets_num; i_bucket++)
{
if (!buckets[i_bucket].size()) continue;//排除空桶
//给当前桶排序(插入排序)
for (int i_sort = 1; i_sort < buckets[i_bucket].size(); i_sort++)
{
int temp_sort = buckets[i_bucket][i_sort];
int j_sort = i_sort - 1;//关键索引
while (j_sort >= 0 && temp_sort < buckets[i_bucket][j_sort])
{
buckets[i_bucket][j_sort + 1] = buckets[i_bucket][j_sort];
j_sort--;
}
buckets[i_bucket][j_sort + 1] = temp_sort;
}
//将排好序的桶数据放回原数组
for (int i_sort = 0; i_sort < buckets[i_bucket].size(); i_sort++)
{
arr[i_origin++] = buckets[i_bucket][i_sort];
}
}
}
10.1 算法思想
n
的输入序列分成两个长度为n/2
的子序列;递归
);合并
成一个最终的排序序列。10.3 代码
//归并排序
//归并执行
void mergeExtract(int* arr, int left, int right, int* temp)
{
//递归结束条件
if (left >= right)
return;
//两个子序列进入下一递归
int mid = left + (right - left) / 2;
mergeExtract(arr, left, mid, temp);
mergeExtract(arr, mid+1, right, temp);
//返回两个排好序的子序列,归并存于temp
//1、初始化4个指针
int begin_1 = left, end_1 = mid;
int begin_2 = mid + 1, end_2 = right;
//2、融合两个子序列大部分,两个begin指针变动
int i_temp = left;
while (begin_1 <= end_1 && begin_2 <= end_2)
{
//将较小的存入temp
if (arr[begin_1] < arr[begin_2]) temp[i_temp++] = arr[begin_1++];
else temp[i_temp++] = arr[begin_2++];
}
//3、收尾工作,第1个子序列/第2个子序列可能剩下。
while (begin_1 <= end_1)
temp[i_temp++] = arr[begin_1++];
while (begin_2 <= end_2)
temp[i_temp++] = arr[begin_2++];
//将temp加入arr中
for (int i = left; i <= right; i++)
arr[i] = temp[i];
}
//归并主函数
void mergeSort(int* arr, int len)
{
int* temp = new int[len]; //temp做arr的辅助
mergeExtract(arr, 0, len - 1, temp);
delete[] temp; //释放内存
}
#include
#include
using namespace std;
void print_arr(int* arr, int len);
void swap(int& a, int& b);
void selectionSort(int* arr, int len);
void insertSort(int* arr, int len);
void quickSort(int* arr, int left, int right);
void heapSort(int* arr, int len);
void shellSort(int* arr, int len);
void countSort(int* arr, int len);
void radixSort(int* arr, int len);
void bucketSort(int* arr, int len);
void mergeSort(int* arr, int len);
int main(int argc, char** argv)
{
int arr[15] = { 44,3,38,5,47,15,36,26,27,2,46,4,19,50,48 };
cout << "排序前:"; print_arr(arr,15);
cout << "正确的排序:2\t3\t4\t5\t15\t19\t26\t27\t36\t38\t44\t46\t47\t48\t50" << endl;
//选择排序
//selectionSort(arr, 15);
//插入排序
//insertSort(arr, 15);
//快速排序
//quickSort(arr, 0, 14);
//堆排序
//heapSort(arr, 15);
//希尔排序
//shellSort(arr, 15);
//计数排序
//countSort(arr, 15);
//基数排序
//radixSort(arr, 15);
//桶排序
//bucketSort(arr, 15);
//归并排序
//mergeSort(arr, 15);
cout << "排序后:"; print_arr(arr, 15);
return 0;
}
void swap(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
void print_arr(int* arr,int len)
{
for (int i = 0; i < len; i++)
cout << arr[i] << "\t";
cout << endl;
}
/--------------------------------------------------------------------------------------------------------------------------------/
x.1 算法思想
x.2 图解
x.3 代码