常见排序算法大全

各种排序算法


以下排序均实现从小到大的排序,且数据相同

冒泡排序

  • 重复地走访过要排序的元素列,依次比较两个相邻的元素,如果顺序(如从大到小、首字母从Z到A)错误就把他们交换过来。
void buttle_sort(int* ar, int len)
{
int temp;
for (int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - i - 1; j++)
{
if (ar[j] < ar[j - 1])
{
temp = ar[j];
ar[j] = ar[j - 1];
ar[j - 1] = temp;
}
}
}
}

选择排序

  • 选择排序是一种简单直观的排序算法。依次从序列中找出最小(最大)的元素,放在开头,再次寻找最小(最大)的元素,放在已排序好 的序列的末尾,以此类推
void choice_sort(int* ar, int len)
{
int temp;
for (int i = 0; i < len - 1; i++)
{
int minIdx = i;
for (int j = i + 1; j < len; j++)
{
minIdx = (ar[minIdx] < ar[j]) ? minIdx : j;
}
temp = ar[i];
ar[i] = ar[minIdx];
ar[minIdx] = temp;
}
}

插入排序

  • 依次遍历元素,寻找一个合适的最小(最大)的元素,并逐个与不合适的元素交换位置,实现插入,最后将其放到一个排好序的有序列表中
void insert_sort(int* ar, int len)
{
int temp;
for (int i = 1; i < len; i++)
{
temp = ar[i];
int j = i;
while (j && ar[j - 1] > temp)
{
ar[j] = ar[j - 1];
j--;
}
ar[j] = temp;
}
}

希尔排序

  • 希尔排序是快速的插入排序,通过引入step(步长)来缩插入排序的待交换位置两个元素之间的距离,并且步长依次减少
//希尔排序
void Shell_sort(int* ar, int len)
{
//拆分进行插入排序
int step = len / 2;
int temp;
while (step)
{
for (int i = step; i < len; i += step)
{
temp = ar[i];
int j = i;
while (j && ar[j - step] > temp)
{
ar[j] = ar[j - step];
j -= step;
}
ar[j] = temp;
}
step /= 2;
}
}

计数排序

  • 计数排序是最简单的排序,把元素的值直接当作下标来使用,通过元素值来形成一个新的序列,基数排序不适用于重复元素与负值元素,需要重新实现细节
void jishu_sort(int* ar, int len, int max)
{
int k = 0;
int lengh = max + 1;
//1. 根据数组中最大的元素创建一个临时数组
int* pTemp = new int[lengh];
//2. 临时数组随便赋一个初始值
for (int i = 0; i < max+1; i++)
{
pTemp[i] = -999;
}
//3. 根据下标排列
for (int i = 0; i < len; i++)
{
pTemp[ar[i]] = ar[i];
}
//4. 重新整理数组
for (int i = 0; i < max+1; i++)
{
if (pTemp[i] != -999)
{
ar[k++] = pTemp[i];
}
}
//释放临时数组
delete[] pTemp;
}

桶排序

  • 相当于改进版的计数排序,创建桶集合,每个桶存放着对应的数字位数,依次遍历数组序列的每一位,把合适的元素放入桶中,最后二维数组桶中按顺序存放着的就是数组排好序的结果
void bucket_sort(int* ar, int len)
{
//1. 创建桶 每一位有10个数字 创建一个10行len列的桶集合
int** pTemp = new int* [10];
for (int i = 0; i < 10; i++)
{
//每一个桶都要有足够的空间装下整个数组的数字
pTemp[i] = new int[len];
}
int bit_data; //存储每一位的数字
int num = 1;
int index = 0;
while (num < BIGGEST)
{
//1. 首先给桶赋初始值
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < len; j++)
{
pTemp[i][j] = -999;
}
}
//2. 数据按每位的数字大小依次进桶
for (int i = 0; i < len; i++)
{
bit_data = ar[i] / num % 10;
//进桶
pTemp[bit_data][i] = ar[i];
}
//3. 桶里的数据覆盖原始数据
index = 0;
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < len; j++)
{
if (-999 != pTemp[i][j])
{
ar[index++] = pTemp[i][j];
}
}
}
//travel(ar, len, false);
num *= 10; //位数依次变化 个 十 百 千
}
for (int i = 0; i < len; i++)
{
//释放列
delete pTemp[i];
}
//释放行
delete[] pTemp;
}

二分查找

  • 给定中间下标,通过分治的思想,找出指定的元素
//循环版 二分查找
bool isthisNUM(int* ar, int len,int num)
{
/*
从小到大
*/
int left = 0;
int right = len - 1;
int middle = 0;
while (left <= right)
{
middle = left + (right - left) / 2;
if (ar[middle] == num)
{
return true;
}
if (num > ar[middle])
{
/*
数字大于中间值
*/
left = middle + 1;
}
else if (num < ar[middle])
{
right = middle - 1;
}
}
return false;
}
//递归版 二分查找
bool isthisNUM_DIGUI(int* ar, int left,int right, int num)
{
int middle = 0;
while (left <= right)
{
middle = left + (right - left) / 2;
if (num > ar[middle])
{
return isthisNUM_DIGUI(ar, middle + 1,
right, num);
}
else if (num < ar[middle])
{
return isthisNUM_DIGUI(ar, left, middle - 1,
num);
}
else
{
return true;
}
}
return false;
}

归并排序

  • 采用分治的思想,将数组利用递归分成若干个子数组,再排序已经分好的子数组,最后再将子数组合并为一个有序数组
//调用归并函数
void Invoking_Func(int* ar, int left, int right)
{
Split_Arr(ar, left, right);
}
//两个数组的拆分排序
void Split_Arr(int* ar, int left, int right)
{
int middle = 0;
if (left < right)
{
middle = left + (right - left) / 2;
//拆分归并
Split_Arr(ar, left, middle);
Split_Arr(ar, middle + 1, right);
//合并算法
Merge_Algorithm(ar, left, middle, right);
}
}
//归并算法
void Merge_Algorithm(int* ar, int left, int middle, int right)
{
int start_left = left; //范围left - middle
int start_right = middle+1; //范围middle+1 - right
int pTemp_index = 0; //临时数组的下标
//1. new创建一个临时存储数组
int* pTemp = new int[right - left + 1];
//2. 两个数组中的元素依次比较,放入临时数组中
while (start_left <= middle && start_right <= right)
{
if (ar[start_left] < ar[start_right])
{
pTemp[pTemp_index++] = ar[start_left++];
}
else
{
pTemp[pTemp_index++] = ar[start_right++];
}
}
//3. 将比较完成后多余的元素放入临时数组中
while (start_left <= middle)
{
pTemp[pTemp_index++] = ar[start_left++];
}
while (start_right <= right)
{
pTemp[pTemp_index++] = ar[start_right++];
}
//4. 临时数组的内容拷贝到原数组
memcpy(ar + left, pTemp, sizeof(int) * (right - left + 1));
//5. 释放临时数组
delete[]pTemp;
}

快速排序

  • 采用分治的思想,指定一个中间值,将数组分成两块,假设左半区要小于(大于)中间值,否则将此不符合的元素放在右半区,右半区要大于(小于)中间,否则将此不符合的元素放在左半区,下标指针依次移动,最终形成一个有序数组
//调用快速排序函数
void Quick_Func(int* ar, int left, int right)
{
quickSort(ar, left, right);
}
//分组排序 快速排序算法
void quickSort(int* ar, int left, int right) {
/*
停止条件: 直到无法分为止
*/
if (left >= right)
{
return;
}
//1. 找一个指定的值作为中间值temp l指向left r指向right
int start_left = left; //不大于的区域 假设ar[start_left]是中间值
int start_right = right; //不小于的区域
int temp = ar[start_left]; //临时中间值
//2. 如果l和r不合并的情况下
while (start_left < start_right)
{
while (start_left < start_right && ar[start_right] >= temp)
{
start_right--;
}
ar[start_left] = ar[start_right];
while (start_left < start_right && ar[start_left] <= temp)
{
start_left++;
}
ar[start_right] = ar[start_left];
}
// 最后 l和r到达同一位置,中间值覆盖ar[l]或ar[r]
ar[start_left] = temp;
/*printf("left:%d,mid:%d,right:%d\n", left, start_left, right);
Show(ar, NUM);*/
//3. 重复分组合并
quickSort(ar, left, start_left - 1);
quickSort(ar, start_left + 1, right);
}

各种排序算法时间比较

在这里插入图片描述

/*
头文件
*/
#pragma once
#include <cstdlib>
#include <ctime>
#include <iostream>
#include <Windows.h>
using namespace std;
#define NUM 100000
#define MAX_NUM 100000
//qsort排序
int comp1(const void* a, const void* b);
class Sort
{
private:
int* ar;
int len;
time_t time1 = 0;
time_t time2 = 0;
public:
//默认构造函数
Sort() { len = 0; ar = nullptr; }
Sort(int l)
{
len = l;
ar = new int[len];
}
Sort(const Sort& s);
//析构函数
~Sort() { delete[] ar; }
//初始化数组
void InitArr();
//遍历数组
void ShowArr(bool fg = false);
//获得数组元素最大值
int Get_max();
//冒泡排序
void bubble_sort();
//选择排序
void choice_sort();
//插入排序
void insert_sort();
//希尔排序
void shell_sort();
//基数排序
void radix_sort(int max);
//桶排序
void bucket_sort();
//归并排序
void merge_sort(int left, int right);
void Merge_Sort(int left, int middle, int right);
//快速排序
void quick_sort(int left, int right);
//接口修改时间
time_t& GetTime1()
{
return time1;
}
time_t& GetTime2()
{
return time2;
}
//接口访问
time_t GetTime1()const
{
return time1;
}
time_t GetTime2()const
{
return time2;
}
int* GetArr()
{
return ar;
}
//重载赋值运算符
Sort& operator=(const Sort& s);
};
/*
实现文件
*/
#include "time.h"
Sort::Sort(const Sort& s)
{
this->len = s.len;
this->ar = new int[this->len];
memcpy(this->ar, s.ar, sizeof(int) * this->len);
}
void Sort::InitArr()
{
for (int i = 0; i < len; i++)
{
ar[i] = rand() % MAX_NUM;
}
}
void Sort::ShowArr(bool fg)
{
if (!fg)
{
cout << "排序前: \n";
}
else
{
cout << "排序后: \n";
}
for (int i = 0; i < len; i++)
{
cout << ar[i] << " ";
}
cout << "\n";
}
int Sort::Get_max()
{
int max = ar[0];
for (int i = 0; i < len; i++)
{
if (max < ar[i])
{
max = ar[i];
}
}
return max;
}
void Sort::bubble_sort()
{
int temp;
for (int i = 0; i < len - 1; i++)
{
for (int j = 0; j < len - i - 1; j++)
{
if (ar[j] > ar[j + 1])
{
temp = ar[j];
ar[j] = ar[j + 1];
ar[j + 1] = temp;
}
}
}
}
void Sort::choice_sort()
{
int minIdx;
int temp;
for (int i = 0; i < len - 1; i++)
{
minIdx = i;
for (int j = i + 1; j < len; j++)
{
minIdx = (ar[minIdx] < ar[j]) ? minIdx : j;
}
temp = ar[i];
ar[i] = ar[minIdx];
ar[minIdx] = temp;
}
}
void Sort::insert_sort()
{
int temp;
int j;
for (int i = 1; i < len; i++)
{
temp = ar[i];
j = i;
while (j && ar[j - 1] >= temp)
{
ar[j] = ar[j - 1];
j--;
}
ar[j] = temp;
}
}
void Sort::shell_sort()
{
//希尔排序 分组进行插入排序
int step = len / 2;
int temp;
int j;
while (step)
{
for (int i = step; i < len; i += step)
{
temp = ar[i];
j = i;
while (j && ar[j - step] >= temp)
{
ar[j] = ar[j - step];
j -= step;
}
ar[j] = temp;
}
step /= 2;
}
}
void Sort::radix_sort(int max)
{
int p_index = 0;
//1. 创建一个足够大的临时数组
int* pTemp = new int[max + 1];
//2. 临时数组赋值初始
for (int i = 0; i < max + 1; i++)
{
pTemp[i] = -999;
}
//3. 对应下标赋值
for (int i = 0; i < len; i++)
{
pTemp[ar[i]] = ar[i];
}
//4. 覆盖回原数组
for (int i = 0; i < max + 1; i++)
{
if (pTemp[i] != -999)
{
ar[p_index++] = pTemp[i];
}
}
delete[] pTemp;
}
void Sort::bucket_sort()
{
int num = 1; //从个位开始
int bit_data; //存储各位数字
//1. 创建临时桶集合
int** p = new int* [10];
for (int i = 0; i < 10; i++)
{
p[i] = new int[len];
}
#if 1
while (num<MAX_NUM)
{
//2. 桶初始化
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < len; j++)
{
p[i][j] = -999;
}
}
//3.各位数字比较 然后入桶
for (int i = 0; i < len; i++)
{
bit_data = ar[i] / num % 10;
p[bit_data][i] = ar[i];
}
//4. 覆盖回原数组
int t_index = 0; //新数组下标
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < len; j++)
{
if (p[i][j] != -999)
{
ar[t_index++] = p[i][j];
}
}
}
num *= 10;
}
#else
#endif
for (int i = 0; i < 10; i++)
{
delete[] p[i];
}
delete[] p;
}
void Sort::merge_sort(int left, int right)
{
int middle = 0;
if (left < right)
{
middle = left + (right - left) / 2;
merge_sort(left, middle);
merge_sort(middle + 1, right);
Merge_Sort(left, middle, right);
}
}
void Sort::Merge_Sort(int left, int middle, int right)
{
int sL = left; //left - middle 范围
int sR = middle + 1; //middle+1 - right 范围
int t_index = 0; //临时数组下标
//1. 创建临时数组
int* pTemp = new int[right - left + 1];
//2. 两个数组中的元素依次比较 放入临时数组
while (sL <= middle && sR <= right)
{
if (ar[sL] < ar[sR])
{
pTemp[t_index++] = ar[sL++];
}
else
{
pTemp[t_index++] = ar[sR++];
}
}
//3. 多余的元素接着放入
while (sL <= middle)
{
pTemp[t_index++] = ar[sL++];
}
while (sR <= right)
{
pTemp[t_index++] = ar[sR++];
}
//4.覆盖回原数组
memcpy(ar + left, pTemp, sizeof(int) * (right - left + 1));
//5.释放临时数组
delete[] pTemp;
}
void Sort::quick_sort(int left, int right)
{
if (left >= right)
{
return;
}
//找中间值 sL和sR与中间值进行比较
int sL = left; //指向数组起点
int sR = right; //指向数组末尾
int temp = ar[sL]; //中间值
//分组进行快排
while (sL < sR)
{
while (sL < sR && ar[sR] >= temp)
{
sR--;
}
ar[sL] = ar[sR];
while (sL < sR && ar[sL] <= temp)
{
sL++;
}
ar[sR] = ar[sL];
}
ar[sL] = temp;
//继续拆分
quick_sort(left, sL - 1);
quick_sort(sL + 1, right);
}
Sort& Sort::operator=(const Sort& s)
{
this->len = s.len;
this->ar = new int[this->len];
memcpy(this->ar, s.ar, sizeof(int) * this->len);
return *this;
}
int comp1(const void* a, const void* b)
{
if (*(int*)a > *(int*)b)
{
return 1;
}
else if (*(int*)a < *(int*)b)
{
return -1;
}
else
{
return 0;
}
}
#include "time.h"
time_t time1 = 0;
time_t time2 = 0;
int main()
{
srand(time(0));
Sort ar1(NUM);
ar1.InitArr();
Sort ar2;
ar2 = ar1;
Sort ar3(ar1);
Sort ar4(ar1);
Sort ar5;
ar5 = ar1;
Sort ar6(ar1);
Sort ar7(ar1);
int* arr_sort = new int[NUM];
memcpy(arr_sort, ar1.GetArr(), sizeof(int) * NUM);
cout << "10w 个数据的排序算法比较: \n\n";
#if 1
#if 1
ar1.GetTime1() = GetTickCount();
ar1.bubble_sort();
ar1.GetTime2() = GetTickCount();
cout << "冒泡排序用时: " << ar1.GetTime2() - ar1.GetTime1()
<< "ms" << endl;
ar2.GetTime1() = GetTickCount();
ar2.choice_sort();
ar2.GetTime2() = GetTickCount();
cout << "选择排序用时: " << ar2.GetTime2() - ar2.GetTime1()
<< "ms" << endl;
ar3.GetTime1() = GetTickCount();
ar3.insert_sort();
ar3.GetTime2() = GetTickCount();
cout << "插入排序用时: " << ar3.GetTime2() - ar3.GetTime1()
<< "ms" << endl;
#endif
ar4.GetTime1() = GetTickCount();
ar4.shell_sort();
ar4.GetTime2() = GetTickCount();
cout << "希尔排序用时: " << ar4.GetTime2() - ar4.GetTime1()
<< "ms" << endl;
ar5.GetTime1() = GetTickCount();
ar5.bucket_sort();
ar5.GetTime2() = GetTickCount();
cout << "桶排序用时: " << ar5.GetTime2() - ar5.GetTime1()
<< "ms" << endl;
ar6.GetTime1() = GetTickCount();
ar6.merge_sort(0,NUM-1);
ar6.GetTime2() = GetTickCount();
cout << "归并排序用时: " << ar6.GetTime2() - ar6.GetTime1()
<< "ms" << endl;
ar7.GetTime1() = GetTickCount();
ar7.quick_sort(0, NUM - 1);
ar7.GetTime2() = GetTickCount();
cout << "快速排序用时: " << ar7.GetTime2() - ar7.GetTime1()
<< "ms" << endl;
time1 = GetTickCount();
qsort(arr_sort, NUM, sizeof(int), comp1);
time2 = GetTickCount();
cout << "qsort排序用时: " << time2 - time1
<< "ms" << endl;
cout << "基数排序暂不在讨论范围内" << endl;
#endif
return 0;
}
``
posted @   hugeYlh  阅读(17)  评论(0编辑  收藏  举报  
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
· AI 智能体引爆开源社区「GitHub 热点速览」
· C#/.NET/.NET Core技术前沿周刊 | 第 29 期(2025年3.1-3.9)
点击右上角即可分享
微信分享提示