【数据结构】计数排序 排序系列所有源代码 复杂度分析(终章)

目录

一,计数排序

1,基本思想

2,思路实现

3,计数排序的特性总结:

二,排序算法复杂度及稳定性分析

三,排序系列所有源代码

Sort.h

Sort.c

Stack.h

Stack.c


一,计数排序

计数排序也叫非比较排序;

1,基本思想

计数排序又称为鸽巢原理,是对哈希直接定址法的变形应用

操作步骤

1,统计相同元素出现次数

2,根据统计的结果将序列回收到原来的序列中

图解原理:

对这样一个不需要比较的排序就完成了;

2,思路实现

// 计数排序
void CountSort(int* arr, int n)
{int i = 0;int max = arr[0], min = arr[0];//找最大,最小值for (i = 0; i < n; i++){if (arr[i] > max){max = arr[i];}if (arr[i] < min){min = arr[i];}}//空间大小int sum = max - min + 1;//开辟空间并且使元素值都为0int* arr1 = (int*)calloc(sum, sizeof(int));//给新数组赋值for (i = 0; i < n; i++){arr1[arr[i] - min]++;}int j = 0;//回收到原来的序列中for (i = 0; i < sum; i++){while (arr1[i]--){arr[j++] = i + min;}}
}

然后我们运行测试一下:

可以看到是有序的,选择排序就 OK 了;

3,计数排序的特性总结:

1, 计数排序在数据范围集中时,效率很高,但是适用范围及场景有限

2.,时间复杂度:O(N+K)

3, 空间复杂度:O(N)

4, 稳定性:稳定

二,排序算法复杂度及稳定性分析

排序方法平均情况最好情况最坏情况辅助空间稳定性
冒泡排序O(N^2)O(N)O(N^2)O(1)稳定
选择排序O(N^2)    O(N^2) O(N^2) O(1)不稳定
直接插入排序O(N^2) O(N)O(N^2)O(1)稳定
希尔排序O(NlongN)~O(N^2)O(N^1.3)O(N^2)O(1)不稳定
堆排序O(NlongN)O(NlongN)O(NlongN)O(1)不稳定
归并排序O(NlongN)O(NlongN)O(NlongN)O(N)稳定
快速排序O(NlongN)O(NlongN)O(N^2)O(N)不稳定
计数排序O(N+K)O(N+K)O(N+K)O(K)稳定

三,排序系列所有源代码

Sort.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#include"Stack.h"//打印
void PrintSort(int* arr, int n);//插入排序
void InsertSort(int* arr, int n);//希尔排序
void HillSort(int* arr, int n);//选择排序
void SeleSort(int* arr, int n);//堆排序
void HeapSort(int* arr, int n);
//向下调整
void DownAdjust(int* arr, int n, int i);冒泡排序
//void BubblSort(int* arr, int n);//快速排序
void QuickSort(int* arr, int begin, int end);
//三数取中
int middle(int* arr, int left, int right);
//快慢指针法
int PartSort3(int* arr, int left, int right);
//挖坑法
int PartSort2(int* arr, int left, int right);
//霍尔排序
int PartSort1(int* arr, int left, int right);
//快速排序(非递归)
void QuickNon(int* arr, int begin, int end);//归并排序
void MergerSort(int* arr, int begin, int end);//归并排序(非递归)
void MergerSortNon(int* arr, int begin, int end);// 计数排序
void CountSort(int* arr, int n);

Sort.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Sort.h"//打印
void PrintSort(int* arr, int n)
{int i = 0;for (i = 0; i < n; i++){printf("%d ", arr[i]);}
}//交换
void Swap(int* a, int* b)
{int tmp = *a;*a = *b;*b = tmp;
}//插入排序
void InsertSort(int* arr, int n)
{int i = 0;for (i = 0; i < n-1; i++){int end = i;int tmp = arr[end + 1];while (end >= 0){if (arr[end] >= tmp){//交换Swap(&arr[end], &arr[end+1]);end--;}else{break;}}arr[end + 1] = tmp;}
}//希尔排序
void HillSort(int* arr, int n)
{int gap = n;int i = 0;while (gap > 1){gap = gap / 2;for (i = 0; i < n-gap; i++){int end = i;int tmp = arr[end + gap];while (end >= 0){if (arr[end] >= tmp){//交换Swap(&arr[end], &arr[end + gap]);end -= gap;}else{break;}}arr[end + gap] = tmp;}}
}//选择排序
void SeleSort(int* arr, int n)
{int begin = 0, end = n - 1;while (begin < end){int maxi = begin, mini = begin;for (int i = begin; i <= end; i++){if (arr[i] > arr[maxi]){maxi = i;}if (arr[i] < arr[mini]){mini = i;}}Swap(&arr[begin], &arr[mini]);// 如果maxi和begin重叠,修正一下即可if (begin == maxi){maxi = mini;}Swap(&arr[end], &arr[maxi]);++begin;--end;}
}//向下调整
void DownAdjust(int* arr, int n, int i)
{int perent = i;int child = perent* 2 + 1;while (child<n){if (child+1<n && arr[child + 1] > arr[child]){child++;}if (arr[perent] < arr[child]){//交换Swap(&arr[perent], &arr[child]);perent = child;child = perent * 2 + 1;}else{break;}}
}//堆排序
void HeapSort(int* arr, int n)
{//建堆int i = 0;for (i = (n - 1 - 1) / 2; i >= 0; i--){//向下调整DownAdjust(arr, n, i);}//交换,删除排序法while (n > 1){//交换Swap(&arr[0], &arr[n - 1]);n--;//向下调整DownAdjust(arr, n, 0);}
}//三数取中
int middle(int* arr, int left, int right)
{//int mid = (left +right)/ 2;//随机数取中int mid = left + (rand() % (right - left));if (arr[left] < arr[mid]){if (arr[mid] < arr[right]){return mid;}if (arr[left] < arr[right]){return right;}else{return left;}}//arr[mid]<=arr[left]else{if (arr[mid] > arr[right]){return mid;}if (arr[left] > arr[right]){return right;}else{return left;}}
}//霍尔排序
int PartSort1(int* arr, int left, int right)
{//三数取中int ret = middle(arr, left, right);Swap(&arr[left], &arr[ret]);int keyi = left;while (left < right){//右边先走while (left<right && arr[right]>=arr[keyi]){right--;}//左边后走while (left < right && arr[left] <= arr[keyi]){left++;}//交换Swap(&arr[left], &arr[right]);}Swap(&arr[left], &arr[keyi]);return left;
}//挖坑法
int PartSort2(int* arr, int left, int right)
{//三数取中int ret = middle(arr, left, right);Swap(&arr[left], &arr[ret]);int key = arr[left];int hole = left;while (left < right){while (left < right && arr[right] >= key){right--;}arr[hole] = arr[right];hole = right;while (left < right && arr[left] <= key){left++;}arr[hole] = arr[left];hole = left;}arr[hole] = key;return hole;
}//前后指针法
int PartSort3(int* arr, int left, int right)
{//三数取中int ret = middle(arr, left, right);Swap(&arr[left], &arr[ret]);int keyi = left;int slow = left, fast = left+1;while (fast<=right){if (arr[fast] < arr[keyi] && ++slow!=fast){//交换Swap(&arr[fast], &arr[slow]);}fast++;}Swap(&arr[slow], &arr[keyi]);return slow;
}//插入排序(改造版)
void InsertSort1(int* arr, int left, int right)
{int i = 0;for (i = left; i < right; i++){int end = i;int tmp = arr[end + 1];while (end >= 0){if (arr[end] >= tmp){//交换Swap(&arr[end], &arr[end + 1]);end--;}else{break;}}arr[end + 1] = tmp;}
}//快速排序
void QuickSort(int* arr, int begin, int end)
{srand(time(0));if (begin >= end){return NULL;}if (end - begin <10){InsertSort1(arr,begin,end);}else{int keyi = PartSort1(arr, begin, end);//排序[begin,keyi) & [keyi+1,end]QuickSort(arr, begin, keyi);QuickSort(arr, keyi + 1, end);}
}//快速排序(非递归)
void QuickNon(int* arr, int begin, int end)
{srand(time(0));ST ps;//初始化STInit(&ps);if (begin >= end){return;}//插入STPush(&ps, end);STPush(&ps, begin);//栈不为空就进去while (!STEmpty(&ps)){int left = STInsert(&ps);//栈顶元素STPop(&ps);//删除int right = STInsert(&ps);STPop(&ps);int keyi = PartSort1(arr, left, right);//排序[left,keyi-1] & [keyi+1,right]if (keyi + 1 < right){//插入STPush(&ps, right);STPush(&ps, keyi + 1);}if (left < keyi - 1){//插入STPush(&ps, keyi - 1);STPush(&ps, left);}}//销毁STDestroy(&ps);
}//归并
void Merger(int* arr, int* tmp,int begin,int end)
{int mid = (begin + end) / 2;if (begin == end){return;}//排序【begin,mid】& 【mid+1,end】Merger(arr, tmp, begin,mid);Merger(arr, tmp, mid+1, end);int begin1 = begin, end1 = mid;int begin2 = mid + 1, end2 = end;int i = 0;while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] < arr[begin2]){tmp[i++] = arr[begin1++];}else{tmp[i++] = arr[begin2++];}}while(begin1 <= end1){tmp[i++] = arr[begin1++];}while (begin2 <= end2){tmp[i++] = arr[begin2++];}//进行拷贝memcpy(arr + begin, tmp, (end - begin+1)*sizeof(int));
}//归并排序
void MergerSort(int* arr, int begin, int end)
{if (begin >= end){return;}//开辟同等大小数组int* tmp = (int*)malloc((end - begin + 1)*sizeof(int));//归并Merger(arr, tmp, begin, end);free(tmp);tmp = NULL;
}//归并排序(非递归)
void MergerSortNon(int* arr, int begin, int end)
{if (begin >= end){return;}//开辟同等大小数组int* tmp = (int*)malloc((end - begin + 1) * sizeof(int));int gap = 1;int j = 0;while (gap < end){for (j = 0; j < end; j += 2 * gap){int begin1 = j, end1 = begin1+gap-1;int begin2 =end1+1, end2 = begin2+gap-1;int i = 0;//处理边界问题if (end1 >= end){break;}if (end2 >end){end2 = end;}while (begin1 <= end1 && begin2 <= end2){if (arr[begin1] < arr[begin2]){tmp[i++] = arr[begin1++];}else{tmp[i++] = arr[begin2++];}}while (begin1 <= end1){tmp[i++] = arr[begin1++];}while (begin2 <= end2){tmp[i++] = arr[begin2++];}//进行拷贝memcpy(arr + j, tmp, (end2 - j+ 1) * sizeof(int));}gap *= 2;}free(tmp);tmp = NULL;
}// 计数排序
void CountSort(int* arr, int n)
{int i = 0;int max = arr[0], min = arr[0];//找最大,最小值for (i = 0; i < n; i++){if (arr[i] > max){max = arr[i];}if (arr[i] < min){min = arr[i];}}//空间大小int sum = max - min + 1;//开辟空间并且使元素值都为0int* arr1 = (int*)calloc(sum, sizeof(int));//给新数组赋值for (i = 0; i < n; i++){arr1[arr[i] - min]++;}int j = 0;//回收到原来的序列中for (i = 0; i < sum; i++){while (arr1[i]--){arr[j++] = i + min;}}
}

Stack.h

#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include<stdbool.h>typedef int STDataType;
typedef struct StackTop
{STDataType* a;int top;int capacity;
}ST;//初始化
void STInit(ST* ps);
//销毁
void STDestroy(ST* ps);
//插入
void STPush(ST* ps, STDataType x);
//删除
void STPop(ST* ps);
//返回栈顶
STDataType STInsert(ST* ps);
//数量
int STSize(ST* ps);
//判断是否为空
int STEmpty(ST* ps);

Stack.c

#define _CRT_SECURE_NO_WARNINGS 1
#include"Stack.h"//初始化
void STInit(ST* ps)
{assert(ps);ps->a = NULL;ps->top = ps->capacity = 0;
}
//销毁
void STDestroy(ST* ps)
{assert(ps);free(ps->a);ps->a = NULL;ps->top = ps->capacity = 0;
}
//插入
void STPush(ST* ps, STDataType x)
{assert(ps);if (ps->top == ps->capacity){ps->capacity = ps->top == 0 ? 4 : ps->capacity*2;ps->a = (STDataType*)realloc(ps->a,sizeof(STDataType)*ps->capacity);}ps->a[ps->top] = x;ps->top++;
}
//删除
void STPop(ST* ps)
{assert(ps);assert(ps->top > 0);ps->top--;
}
//返回栈顶
STDataType STInsert(ST* ps)
{assert(ps);assert(ps->top > 0);return ps->a[ps->top-1];
}
//数量
int STSize(ST* ps)
{assert(ps);return ps->top;
}
//判断是否为空
int STEmpty(ST* ps)
{assert(ps);if (ps->top == 0){return 1;}else{return 0;}
}

同志们!排序的知识就到这里了!

后面博主会陆续更新;

如有不足之处欢迎来补充交流!

完结。。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/151993.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

厌烦了iPhone默认的热点名称?如何更改iPhone上的热点名称

你对你默认的热点名称感到厌倦了吗&#xff1f;这篇文章是为你准备的。在这里&#xff0c;你可以了解如何轻松更改iPhone上的热点名称。 个人热点会将你的手机数据转换为Wi-Fi信号。手机上的个人热点使用户能够与其他用户共享其蜂窝数据连接。当你在WIFI网络之外时&#xff0c…

使用华为eNSP组网试验⑹-组建基于BGP的网络

BGP(Border Gateway Protocol -- 边界网关协议)是一种在自治系统之间动态交换路由信息、具有丰富的路由控制机制、稳定而安全的路由协议&#xff0c;一般部署在骨干(主要、核心)路由器。 BGP适用于大中型网络的组建&#xff0c;在很多企业当中都有应用。 一般情况下&#xff0c…

网关、网桥、路由器和交换机之【李逵与李鬼】

概念 网关 网关简单来说是连接两个网络的设备,现在很多局域网都是采用路由器来接入网络,因此现在网关通常指的就是路由器的IP。网关可用于家庭或者小型企业,连接局域网和Internet,也有用于工业应用的。 网桥 网桥也叫桥接器,是连接两个局域网的一种存储/转发设备,它能…

Linux搭建我的世界MC服务器 【Minecraft外网联机教程】

目录 前言 1. 安装JAVA 2. MCSManager安装 3.局域网访问MCSM 4.创建我的世界服务器 5.局域网联机测试 6.安装cpolar内网穿透 7. 配置公网访问地址 8.远程联机测试 9. 配置固定远程联机端口地址 9.1 保留一个固定tcp地址 9.2 配置固定公网TCP地址 9.3 使用固定公网…

基于Java的在线文档编辑管理系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

上门按摩小程序|同城上门按摩软件开发|上门按摩系统;

上门按摩小程序的开发具有许多优势&#xff0c;下面就给大家介绍下按摩小程序功能: 上门按摩小程序的优势 方便快捷&#xff1a;上门按摩小程序提供在线预约服务&#xff0c;用户可以通过手机随时随地预约按摩师上门服务&#xff0c;避免了传统预约方式的繁琐和不确定性。 个性…

数据结构-二叉查找树(BST)

二叉查找树 需要满足这些规则&#xff1a; 左子节点小于父节点右子节点大于父节点 查找的效率 非常好&#xff0c;每次都能根据大小去舍弃另一半的分支&#xff0c;极大的减少的比对次数 具体的性能&#xff0c;取决于树的层数和平衡程度。 BST树的节点 struct Node {No…

qt5.14.2+VS源码调试记录

在对qt使用时&#xff0c;有时需要对源代码进行调试&#xff0c;方便进行问题定位和debug&#xff0c;但直接安装的qt不能进入qt源码&#xff0c;需要进行一定的操作才能进行源码调试和定位。 源码调试需要对应版本的pdb文件&#xff0c;可以在官网下载&#xff0c;也可找其它…

2023年台州市第三届网络安全技能大赛(MISC)—Black Mamba

前言&#xff1a;当时比赛没有做出来现在来复现一下 就当记录一下&#xff08;这个思路没想到&#xff09; Black Mamba&#xff1a; 一张图片 常规得分离&#xff0c;属性&#xff0c;LSB&#xff0c;盲水印等都尝试过 无果&#xff01; 考点&#xff1a;异或解密&#xff0…

Flutter学习笔记

此篇文章用来记录学习Flutter 和 Dart 相关知识 零.Dart基本数据类型 Dart 是一种静态类型的编程语言&#xff0c;它提供了一系列基本数据类型&#xff0c;用于存储和操作不同种类的数据。以下是 Dart 中的一些基本数据类型以及它们的详细介绍&#xff1a; 1. 整数类型&#…

企业服务器租用对性能有什么要求呢?

企业租用服务器租用首要的是稳定&#xff0c;其次是安全&#xff0c;稳定是为了让企业的工作能够顺利进行&#xff0c;只有性能稳定的服务器才能保证网站之类的正常工作&#xff0c;就让小编带大家看一看有什么要求吧&#xff01; 服务器简单介绍。服务器是在网络上为其它客户机…

Unit3 使用 uniCloud 制作书籍管理移动端应用项目

Unit3 使用 uniCloud 制作书籍管理移动端应用项目 1 构建项目并关联云服务空间2 为项目准备数据库表3 schema2Code4 遇到了错误5 对 "addtime" 字段对应的前端组件进行修改6 首次运行 1 构建项目并关联云服务空间 uniCloud 为开发人员提供了“阿里云”和“腾讯云”两…

边坡安全监测系统:守护边坡稳定的重要工具

在工程建设中&#xff0c;边坡安全监测系统一直被认为是掌握边坡安全及其支护结构维护决策系统的关键支撑条件。这一系统的主要目的在于确定边坡结构的稳定性&#xff0c;监控支护结构的承载能力、运营状态和耐久性能&#xff0c;并对边坡稳定性进行实时监控。 一、边坡安全监测…

竞赛选题 深度学习 python opencv 火焰检测识别 火灾检测

文章目录 0 前言1 基于YOLO的火焰检测与识别2 课题背景3 卷积神经网络3.1 卷积层3.2 池化层3.3 激活函数&#xff1a;3.4 全连接层3.5 使用tensorflow中keras模块实现卷积神经网络 4 YOLOV54.1 网络架构图4.2 输入端4.3 基准网络4.4 Neck网络4.5 Head输出层 5 数据集准备5.1 数…

react-antd 文件导入按钮增加一个加载状态

1、效果图实例: 2、部分代码 2.1 props : 2.2 handleChange、上传的文件检验 : construction中定义 construction(props) { super(props); this.state { loadingStaus: flase, loadingDisabled: flase, // 作用:按钮如果在加 载状态中&#xff0c;没…

Node.js代码漏洞扫描工具介绍——npm audit

npm audit 运行安全检查 主要作用&#xff1a;检查命令将项目中配置的依赖项的描述提交到默认注册中心&#xff0c;并要求报告已知漏洞。如果发现任何漏洞&#xff0c;则将计算影响和适当的补救措施。如果 fix 提供了参数&#xff0c;则将对包树应用补救措施。 具体参考&#x…

【面向校招】Golang 常考面试题汇总 持续更新中...

前言: 为了方便自己复习和巩固,基础知识,整理了这个面试题汇总 文章目录 Go基础1. 讲一讲go中slice底层2. 讲一讲go中Map底层3. 讲一讲go中channel底层4. go中的并发编程MutexMysql1)数据库的三大范式2)关系型数据库和非关系型数据库的优缺点对比,应用场景3)MySQL和Mong…

机器视觉工程师,我们上班的意义在哪里?

很多朋友&#xff0c;现在不是自己想做的工作&#xff0c;那你做这份工作干什么&#xff1f;担心自己没有竞争力&#xff0c;担心自己被替代。上班的意义是完成自己头脑和资源的原始积累&#xff0c;迈向下一级人生游戏;我最终要靠自己本事吃饭&#xff0c;而不是一直待在这个只…

Tensorflow入门之 Hello World

Tensorflow入门之 Hello World 简介 Tensorflow 是 Google 开源的深度学习框架&#xff0c;来自于 Google Brain 研究项目&#xff0c;在 Google 第一代分布式机器学习框架 DistBelief 的基础上发展起来。 Tensorflow 的官方网址 http://www.tensorflow.org Tensorflow 的 G…

Stm32_标准库_8_ADC_光敏传感器_测量具体光照强度

ADC简介 测量方式 采用二分法比较数据 IO通道 ADC基本结构及配置路线 获取数字变量需要用到用到光敏电阻的AO口&#xff0c;AO端口接在PA0引脚即可 测得的模拟数据与实际光照强度之间的关系为 光照强度 100 - 模拟量 / 40;代码&#xff1a; 完整朴素代码&#xff1a; #in…