当前位置: 首页 > news >正文

数据结构 | 排序 - 总结

排序的方式

在这里插入图片描述

排序的稳定性

  • 什么是排序的稳定性?
    不改变相同数据的相对顺序

  • 排序的稳定性有什么意义?

    • 假定一个场景:
      一组成绩:100,88,98,98,78,100(按交卷顺序排列,先交在前)
      先需要对这组数据按降序排列,如果分数相同,先交卷的排在前面。

在以上这种场景下,选择具有稳定性的排序方式就很有必要。

排序方式分析比较汇总

排序方式时间复杂度空间复杂度稳定性
InsertO(N2)O(1)
ShellO(N1.3)O(1)×(预排序相同数可能分到不同组)
SelectO(N2)O(1)×(9,9,4,4)(swap(4,9)后4和4的相对顺序改变)
HeapO(N*logN)O(1)×
BubbleO(N2)O(1)
QuickO(N*logN)(大量重复数据:N2O(logN)(递归调用栈帧)×(最后相遇那下交换会打乱)
MergeO(N*logN)O(N+(logN) )
CountO(N+range)O(range)×

912.排序数组 - 力扣(LeetCode)

👉题目链接

/*** Note: The returned array must be malloced, assume caller calls free().*///栈
// 支持动态增长的栈
typedef int STDataType;
typedef struct Stack
{STDataType* _a;int _top;		// 栈顶int _capacity;  // 容量 
}Stack;
// 初始化栈 
void StackInit(Stack* ps)
{STDataType* tmp = (STDataType*)malloc(4 * sizeof(STDataType));if (!tmp){perror("malloc fail");exit(-1);}ps->_a = tmp;ps->_top = 0;ps->_capacity = 4;
}
// 入栈 
void StackPush(Stack* ps, STDataType data)
{assert(ps);if (ps->_capacity == ps->_top){STDataType* tmp = (STDataType*)realloc(ps->_a, 2 * ps->_capacity * sizeof(STDataType));if (!tmp){perror("realloc fail");exit(-1);}ps->_a = tmp;ps->_capacity *= 2;}ps->_a[ps->_top] = data;ps->_top++;
}
// 出栈 
void StackPop(Stack* ps)
{assert(ps);assert(!StackEmpty(ps));assert(ps->_top);ps->_top--;}
// 获取栈顶元素 
STDataType StackTop(Stack* ps)
{assert(ps);assert(ps->_top);return ps->_a[ps->_top - 1];
}
// 获取栈中有效元素个数 
int StackSize(Stack* ps)
{assert(ps);return ps->_top;
}
// 检测栈是否为空,如果为空返回非零结果,如果不为空返回0 
int StackEmpty(Stack* ps)
{assert(ps);return ps->_top == 0;
}
// 销毁栈 
void StackDestroy(Stack* ps)
{assert(ps);free(ps->_a);ps->_capacity = ps->_top = 0;ps->_a = NULL;
}//插入排序
void InsertSort(int* a, int n)
{assert(a);for (int i = 1; i < n; i++){int tmp = a[i];int end = i - 1;while (end >= 0){if (a[end] <= tmp){break;}//a[end + 1] = a[end--];???为什么错误a[end + 1] = a[end];end--;}a[end + 1] = tmp;}}// 希尔排序
void ShellSort(int* a, int n)
{assert(a);int gap = n / 2;while (gap){for (int i = 1; i < n; i++){int tmp = a[i];int end = i - gap;while (end >= 0){if (a[end] <= tmp){break;}a[end + gap] = a[end];end -= gap;}a[end + gap] = tmp;}gap /= 2;}
}void Swap(int* x, int* y)
{assert(x && y);int tmp = *x;*x = *y;*y = tmp;
}// 选择排序
void SelectSort(int* a, int n)
{assert(a);int begin = 0, end = n - 1;while (begin < end){int mini = begin, maxi = end;//[begin+1,end-1]for (int j = begin; j <= end; j++){if (a[j] < a[mini])mini = j;if (a[j] > a[maxi])maxi = j;}//swap之前 min==a[mini]  max==a[maxi]Swap(&a[begin], &a[mini]);//swap之后:begin → min ; mini → original-a[begin]//if(original-a[begin] → max)则会影响 a[maxi] =? maxif (begin == maxi)//如果原本begin指向的数是max,则swap之后这个数已经被交换到了mini所指向的位置maxi = mini;Swap(&a[end], &a[maxi]);++begin;--end;}
}// 堆排序
void AdjustDwon(int* a, int n, int root)
{assert(a);int parent = root;int child = parent * 2 + 1;while (child < n){if ((child + 1) < n && a[child + 1] > a[child])++child;if (a[parent] < a[child])Swap(&a[parent], &a[child]);elsebreak;parent = child;child = parent * 2 + 1;}
}
void HeapSort(int* a, int n)
{assert(a);//建大堆for (int parent = (n - 1 - 1) / 2; parent >= 0; parent--){AdjustDwon(a, n, parent);}int end = n - 1;while (end){Swap(&a[0], &a[end]);AdjustDwon(a, end, 0);end--;}
}
// 冒泡排序
void BubbleSort(int* a, int n)
{assert(a);for (int j = 0; j < n; j++){for (int i = 0; i < n - j - 1; i++){if (a[i] > a[i + 1])Swap(&a[i], &a[i + 1]);}}
}// 快速排序递归实现
// 三数取中
int GetMidIndex(int* a, int left, int right)
{int begin = left, end = right;int middle = (left + right) / 2;if (a[begin] < a[end]){if (a[middle] < a[begin])return begin;else if (a[middle] > a[end])return end;elsereturn middle;}else{if (a[middle] < a[end])return end;else if (a[middle] > a[begin])return begin;elsereturn middle;}}
// 快速排序hoare版本
int hoareSort1(int* a, int left, int right)
{assert(a);if (left >= right)return;// if ((right - left + 1) < 5)// {// 	InsertSort(a + left, right - left + 1);// }else{int key = left, begin = left, end = right;int mid = GetMidIndex(a, left, right);Swap(&a[mid], &a[key]);while (left < right){while (left < right && a[right] >= a[key]){--right;}while (left < right && a[left] <= a[key]){++left;}Swap(&a[left], &a[right]);}Swap(&a[key], &a[right]);//left==right//[begin,left-1] [right+1,end]hoareSort1(a, begin, left - 1);hoareSort1(a, right + 1, end);}return right;
}// 快速排序挖坑法
int HoleSort2(int* a, int left, int right)
{if (left >= right)return;int key = a[left];int hole = left, begin = left, end = right;while (left < right){while (left < right && a[right] >= key){--right;}a[hole] = a[right];hole = right;while (left < right && a[left] <= key){++left;}a[hole] = a[left];hole = left;}a[right] = key;//[begin,left-1] [right+1,end]HoleSort2(a, begin, left - 1);HoleSort2(a, right + 1, end);return right;
}// 快速排序前后指针法
int PointSort3(int* a, int left, int right)
{assert(a);if (left >= right)return;int keyi = left;int prev = left, cur = left;while (cur <= right){if (a[cur] < a[keyi] && cur != prev)Swap(&a[++prev], &a[cur]);++cur;}Swap(&a[keyi], &a[prev]);//[left,prev-1][prev+1,right]PointSort3(a, left, prev - 1);PointSort3(a, prev + 1, right);return prev;
}// 快速排序 非递归实现
void QuickSort(int* a, int left, int right)
{assert(a);Stack st;StackInit(&st);StackPush(&st, left);StackPush(&st, right);while (!StackEmpty(&st)){int end = StackTop(&st);StackPop(&st);int begin = StackTop(&st);StackPop(&st);int keyi = hoareSort1(a, begin, end);//[begin,keyi-1] keyi [keyi+1,end]if (keyi + 1 < end){StackPush(&st, keyi + 1);StackPush(&st, end);}if (begin < keyi - 1){StackPush(&st, begin);StackPush(&st, keyi - 1);}}StackDestroy(&st);
}
// 归并排序递归实现
void _MergeSort(int* a, int left, int right, int* tmp)
{assert(a && tmp);if (left == right)return;int middle = (left + right) / 2;//[left,  middle] [middle+1,right]//[begin1,end1]   [begin2,end2]int begin1 = left, end1 = middle, begin2 = middle + 1, end2 = right;//递归分解_MergeSort(a, begin1, end1, tmp);_MergeSort(a, begin2, end2, tmp);//mergeint i = begin1;while (begin1 <= end1 && begin2 <= end2){if (a[begin1] <= a[begin2]){tmp[i++] = a[begin1++];}else{tmp[i++] = a[begin2++];}}while (begin1 <= end1){tmp[i++] = a[begin1++];}while (begin2 <= end2){tmp[i++] = a[begin2++];}memcpy(a + left, tmp + left, sizeof(int) * (right - left + 1));
}
void MergeSort(int* a, int n)
{assert(a);int* tmp = (int*)malloc(sizeof(int) * n);if (!tmp){perror("malloc fail");exit(-1);}_MergeSort(a, 0, n - 1, tmp);free(tmp);tmp = NULL;
}// 归并排序非递归实现
void MergeSortNonR(int* a, int n)
{assert(a);int* tmp = (int*)malloc(sizeof(int) * n);if (!tmp){perror("malloc fail");exit(-1);}int range = 1;while (range < n){for (int i = 0; i < n; i += 2 * range){int begin1 = i, end1 = i + range - 1;int begin2 = i + range, end2 = i + 2 * range - 1;int j = begin1;//越界//end1越界if (end1 >= n){end1 = n - 1;begin2 = end2 + 1;//begin2 > end2;}else if (begin2 == n){begin2 = end2 + 1;//begin2 > end2;}else if (end2 >= n){end2 = n - 1;}//mergewhile (begin1 <= end1 && begin2 <= end2){if (a[begin1] <= a[begin2]){tmp[j++] = a[begin1++];}else{tmp[j++] = a[begin2++];}}while (begin1 <= end1){tmp[j++] = a[begin1++];}while (begin2 <= end2){tmp[j++] = a[begin2++];}}memcpy(a, tmp, sizeof(int)*n);range *= 2;}free(tmp);tmp = NULL;
}// 计数排序
void CountSort(int* a, int n)
{assert(a);int min = a[0], max = a[0];for (size_t i = 0; i < n; i++){if (a[i] > max)max = a[i];if (a[i] < min)min = a[i];}int size = max - min + 1;int* tmp = (int*)calloc(size, sizeof(int));if (!tmp){perror("calloc fail");exit(-1);}//计数for (size_t i = 0; i < n; i++){++tmp[*(a + i) - min];}int j = 0;for (size_t i = 0; i < size; i++){while (tmp[i]--){a[j++] = i + min;}}free(tmp);tmp = NULL;
}int* sortArray(int* nums, int numsSize, int* returnSize){*returnSize=numsSize;//InsertSort(nums,numsSize);//超出时间限制//ShellSort(nums,numsSize);//SelectSort(nums,numsSize);//超出时间限制//HeapSort(nums,numsSize);//BubbleSort(nums,numsSize);//超出时间限制//hoareSort1(nums,0,numsSize-1);//对于大量重复数据,超出时间限制//HoleSort2(nums,0,numsSize-1);//超出时间限制//PointSort3(nums,0,numsSize-1);//对于大量有序数据,超出时间限制//QuickSort(nums,0,numsSize-1);//对于大量重复数据,超出时间限制//MergeSort(nums,numsSize);//MergeSortNonR(nums,numsSize);//CountSort(nums,numsSize);return nums;
}

相关文章:

数据结构 | 排序 - 总结

排序的方式 排序的稳定性 什么是排序的稳定性&#xff1f; 不改变相同数据的相对顺序 排序的稳定性有什么意义&#xff1f; 假定一个场景&#xff1a; 一组成绩&#xff1a;100&#xff0c;88&#xff0c;98&#xff0c;98&#xff0c;78&#xff0c;100&#xff08;按交卷顺序…...

crontab -e 系统定时任务

crontab -e解释 crontab 是由 “cron” 和 “table” 两个单词组成的缩写。其中&#xff0c;“cron” 是一个在 Linux 和类 Unix 操作系统中用于定时执行任务的守护进程&#xff0c;而 “table” 则是指一个表格或者列表&#xff0c;因此 crontab 就是一个用于配置和管理定时任…...

前后端交互系列之Axios详解(包括拦截器)

目录 前言一&#xff0c;服务器的搭建二&#xff0c;Axios的基本使用2.1 Axios的介绍及页面配置2.2 如何安装2.3 Axios的前台代码2.4 Axios的基本使用2.5 axios请求响应结果的结构2.6 带参数的axios请求2.7 axios修改默认配置 三&#xff0c;axios拦截器3.1 什么是拦截器3.2 拦…...

定时任务之时间轮算法

初识时间轮 我们先来考虑一个简单的情况&#xff0c;目前有三个任务A、B、C&#xff0c;分别需要在3点钟&#xff0c;4点钟和9点钟执行&#xff0c;可以把时间想象成一个钟表。 如上图中所示&#xff0c;我只需要把任务放到它需要被执行的时刻&#xff0c;然后等着时针转到这个…...

实验4 Matplotlib数据可视化

1. 实验目的 ①掌握Matplotlib绘图基础&#xff1b; ②运用Matplotlib&#xff0c;实现数据集的可视化&#xff1b; ③运用Pandas访问csv数据集。 2. 实验内容 ①绘制散点图、直方图和折线图&#xff0c;对数据进行可视化&#xff1b; ②下载波士顿数房价据集&#xff0c;并…...

【软件工程】为什么要选择软件工程专业?

个人主页&#xff1a;【&#x1f60a;个人主页】 文章目录 前言软件工程&#x1f4bb;&#x1f4bb;&#x1f4bb;就业岗位&#x1f468;‍&#x1f4bb;&#x1f468;‍&#x1f4bb;&#x1f468;‍&#x1f4bb;就业前景&#x1f6e9;️&#x1f6e9;️&#x1f6e9;️工作环…...

5类“计算机”专业很吃香,人才缺口巨大,就业前景良好

说到目前最热门的专业&#xff0c;计算机绝对占有一席之地&#xff0c;是公认的发展前景好、人才缺口大的专业。有人称该专业人数如此众多&#xff0c;势必会导致人才饱和&#xff0c;但是从当前社会互联网发展的趋势来看&#xff0c;计算机专业在很长一段时间都是发展很好的专…...

数仓选型对比

1、数仓选型对比如下(先列举表格&#xff0c;后续逐个介绍) 数仓应用目标产品特点适用于 适用数据类型数据处理速度性能拓展 实施难度运维难度性能优化成本传统数仓(SQLServer、Oracle等关系型数据库)面向主题设计的&#xff0c;为 分析数据而设计基于Oracle、 SQLServer、MyS…...

二叉树的遍历(前序、中序、后序)Java详解与代码实现

递归遍历 前序&#xff0c;中序&#xff0c;后序 /*** Definition for a binary tree node.* public class TreeNode {* int val;* TreeNode left;* TreeNode right;* TreeNode() {}* TreeNode(int val) { this.val val; }* TreeNode(int val, Tree…...

如何找出消耗CPU最多的线程?

如何找出消耗CPU最多的线程&#xff1f; 1.使用 top -c 找出所有当前进程的运行列表 top -c 2.按P(Shiftp)对所有进程按CPU使用率进行排序&#xff0c;找出消耗最高的线程PID ​​​ 显示Java进程 PID 为 136 的java进程消耗最 3.使用 top -Hp PID&#xff0c;查出里面消…...

【论文笔记】Attention Augmented Convolutional Networks(ICCV 2019 入选文章)

目录 一、摘要 二、介绍 三、相关工作 卷积网络Convolutional networks&#xff1a; 网络中注意力机制Attention mechanisms in networks&#xff1a; 四、方法 1. 图像的自注意力Self-attention over images&#xff1a; 二维位置嵌入Two-dimensional Positional Enco…...

虚幻图文笔记:Character Creator 4角色通过AutoSetup For Unreal Engine插件导入UE5.1的过程笔记

在UE5端安装AutoSetup For Unreal Engine插件 AutoSetup For Unreal Engine是Reallusion官方提供的免费插件&#xff0c;官方下载地址&#xff0c;下载到的是一个可执行文件&#xff0c;点击安装&#xff0c;记住安装的位置⬇ 看装完毕后会打开一个文件夹&#xff0c;这里就是对…...

JAVAWeb04-DOM

1. DOM 1.1 概述 1.1.1 官方文档 地址: https://www.w3school.com.cn/js/js_htmldom.asp 1.1.2 DOM 介绍 DOM 全称是 Document Object Model 文档对象模型就是把文档中的标签&#xff0c;属性&#xff0c;文本&#xff0c;转换成为对象来管理 1.2 HTML DOM&#xff08;文档…...

C++内存管理基础知识

C 内存管理 C内存管理是一个重要的主题&#xff0c;因为它涉及到程序运行时资源的分配和释放。它可以分为三种类型&#xff1a;静态内存、栈内存和堆内存。 静态内存 静态内存&#xff08;Static Memory&#xff09;&#xff1a;静态内存用于存储全局变量、静态变量和常量。这…...

命令执行漏洞概述

命令执行漏洞概述 命令执行定义命令执行条件命令执行成因命令执行漏洞带来的危害远程命令执行漏洞相关函数assert()preg_replace()call_user_func() a ( a( a(b)可变函数远程命令执行漏洞的利用系统命令执行漏洞相关函数system()exec()shell_exec()passthru&#xff08;&#x…...

【初试复试第一】脱产在家二战上岸——上交819考研经验

笔者来自通信考研小马哥23上交819全程班学员 先介绍一下自己&#xff0c;我今年初试426并列第一&#xff0c;加上复试之后总分600&#xff0c;电子系第一。 我本科上交&#xff0c;本科期间虽然没有挂科但是成绩排名处于中下游水平。参加过全国电子设计大赛&#xff0c;虽然拿…...

PTA:C课程设计(7)

山东大学&#xff08;威海&#xff09;2022级大一下C习题集&#xff08;7&#xff09; 函数题7-6-1 递增的整数序列链表的插入7-6-2 查找学生链表7-6-3 统计专业人数7-6-4 建立学生信息链表 编程题7-7-1 查找书籍7-7-2 找出总分最高的学生 函数题 7-6-1 递增的整数序列链表的插…...

POSTGRESQL LINUX 与 PG有关的内存参释义

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…...

Docker的常见命令

前言:使用Docker得学会的几个常见命令 常见命令前置学习: docker --help这个命令必须得会因为,很多命令是记不住的,得使用他们的官方help下面是一些实例 docker load --help常见命令集合: 一: docker images #查看全部镜像 docker rmi #删除某个镜像(例如:docker rmi redis…...

详细介绍性能测试的方法(含文档)

性能测试是软件测试中的一个重要环节&#xff0c;其目的是评估系统在不同负荷下的性能表现&#xff0c;包括响应时间、吞吐量、并发数等指标。通常可以通过以下几种方法进行性能测试&#xff1a; 1、负载测试 负载测试是模拟多用户同时访问系统&#xff0c;测试系统在高并发、…...

深入剖析 Qt QHash :原理、应用与技巧

目录标题 引言QHash 基础用法基础用法示例基础用法综合示例 QHash 的高级用法迭代器&#xff1a;遍历 QHash 中的元素&#xff08;Iterators: Traversing Elements in QHash &#xff09;QHash和其他容器的对比QHash 和 std::unordered\_map QHash的底层原理和内存管理QHash 的…...

技术分享 | MySQL级联复制下进行大表的字段扩容

作者&#xff1a;雷文霆 爱可生华东交付服务部 DBA 成员&#xff0c;主要负责Mysql故障处理及相关技术支持。爱好看书&#xff0c;电影。座右铭&#xff0c;每一个不曾起舞的日子&#xff0c;都是对生命的辜负。 本文来源&#xff1a;原创投稿 *爱可生开源社区出品&#xff0c;…...

工业互联网业务知识

文章目录 背景第四次工业革命带动制造业产业升级主要工业大国不同路径 架构ISA95体系架构变革趋势基础通用架构数据采集平台 工业互联网应用软件工业互联网全要素连接产品视角&#xff1a;产销服务企业的业务流程企业数字化改造&#xff1a;车间级全要素连接 工业互联网的产品体…...

jsp+java自行车租赁租借和买卖系统

自行车租借和买卖系统 系统包括四个模块。1&#xff0c;系统模块&#xff0c;2&#xff0c;车辆管理模块&#xff0c;3.租借车管理模块&#xff0c;4&#xff0c;买卖车管理模块。 1&#xff0c;系统模块包括: 连接数据库&#xff0c;工作人员登录&#xff0c;退出。 2&#…...

Python3 字符串

Python3 字符串 字符串是 Python 中最常用的数据类型。我们可以使用引号( 或 " )来创建字符串。 创建字符串很简单&#xff0c;只要为变量分配一个值即可。例如&#xff1a; var1 Hello World! var2 "Runoob" Python 访问字符串中的值 Python 不支持单字符…...

Day943.持续集成流水线 -系统重构实战

持续集成流水线 Hi&#xff0c;我是阿昌&#xff0c;今天学习记录的是关于持续集成流水线的内容。 从团队协作的角度上来看&#xff0c;在版本发布过程中&#xff0c;经常出现测试依赖开发手工生成制品、版本发布也从开发本地出版本的问题。而且项目架构如果从单体演进至组件…...

How to use CCS to debug a running M4F core that was started by Linux?

参考FAQ:AM62x & AM64x: How to use CCS to debug a running M4F core that was started by Linux? 问题记录&#xff1a; 1.使用SD卡启动模式&#xff0c;板上运行Linux。 当Linux系统启动后&#xff0c;9表示M4F core&#xff1a; am64xx-evm login: root rootam64xx…...

216、组合总数III

难度&#xff1a;中等 找出所有相加之和为 n 的 k 个数的组合&#xff0c;且满足下列条件&#xff1a; 只使用数字1到9 每个数字 最多使用一次 返回 所有可能的有效组合的列表 。该列表不能包含相同的组合两次&#xff0c;组合可以以任何顺序返回。 示例 1: 输入: k 3, n 7…...

简单的重装系统教程

郁闷&#xff0c;最近电脑一直蓝屏重启&#xff0c;用 2 分钟就蓝屏一次&#xff0c;遂产生重装系统的想法。 准备 U盘(8G或以上) PE 工具&#xff1a; 微PE工具箱快速指引 | 微PE优盘使用说明书 (wepe.com.cn) 系统镜像&#xff1a; 官网 Windows 10 官网 Windows 11 M…...

机器学习---集成学习报告

1.原理以及举例 1.1原理 集成学习&#xff08;Ensemble Learning&#xff09;是一种机器学习策略&#xff0c;它通过结合多个基学习器&#xff08;base learners&#xff09;的预测来提高模型的性能。集成学习的目标是创建一个比单个基学习器更准确、更稳定的最终预测模型。这…...