*快排延伸-自省排序
此节是学有余力的人去看,如果没时间,不看也没关系,只要知道代码就可以了!
自省排序的思路是自我侦测和反省,快速排序如果递归深度太深,其算法的效率可能被大幅度削弱,这就需要借助其他的算法进行排序了,所以我们需要把之前所有算法都要使用上,至于思想大家可以去搜搜资料,这个算法的代码过长,所以实现起来很麻烦,但是算法思路我之前都已经讲过,里面有些难以理解的地方,这只是一个代码分享的过程,没必要追究如何得到的这个结论,我只在适当地方进行注释。我改变的代码在第465行。代码如下:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
#include <assert.h>
#include <ctype.h>
#include<stdbool.h>
#include<stddef.h>//NULL
#include<time.h>
//交换函数
void Swap(int* a, int* b)
{int p = *a;*a = *b;*b = p;
}
//直接插入排序(升序)
void InsertSort1(int* arr, int n)
{for (int i = 0; i < n - 1; i++){//我们把需要比较的数放入tmp中,然后先与第i个数据比较,依次往前进行比较插入int end = i;int tmp = arr[end + 1];while (end >= 0){if (arr[end] > tmp){arr[end + 1] = arr[end];end--;}else{break;}}//如果end=-1我们不能进行数组越界,所以要进行+1操作arr[end + 1] = tmp;}
}
//希尔排序
void ShellSort1(int* arr, int n)
{int gap = n;while (gap > 1){gap = gap / 3 + 1;for (int i = 0; i < n - gap; i++){int end = i;int tmp = arr[end + gap];while (end >= 0){if (arr[end] > tmp){arr[end + gap] = arr[end];end -= gap;}else{break;}}arr[end + gap] = tmp;}}
}
//直接选择排序
void SelectSort1(int* arr, int n)
{int begin = 0, end = n - 1;while (begin < end){int max, min;max = min = begin;for (int i = begin + 1; i <= end; i++){//我们从开始位置后面的数据进行遍历,原因不用解释if (arr[i] < arr[min]){min = i;}if (arr[i] > arr[max]){max = i;}}if (max == begin){max = min;}Swap(&arr[min], &arr[begin]);Swap(&arr[max], &arr[end]);begin++;end--;}
}//堆的结构
//能存储的数据有很多种typedef int HPDataType;
typedef struct Heap
{HPDataType* arr;int size;//有效数据的个数int capacity;//容量
}HP;
//堆的初始化
void HPInit(HP* php)
{assert(php);php->arr = NULL;php->size = php->capacity = 0;
}
//堆的销毁
void HPDesTory(HP* php)
{//判断是否为NULLif (php->arr){free(php->arr);}php->arr = NULL;php->size = php->capacity = 0;
}
//向上调整算法
void AdjustUp(HPDataType* arr, int child)
{HPDataType parent = (child - 1) / 2;while (child > 0){if (arr[child] > arr[parent]){Swap(&arr[child], &arr[parent]);//或者可以加个continue,之后把else去掉,只留break;child = parent;parent = (child - 1) / 2;}else{break;}}
}
//插入数据
void HPPush(HP* php, HPDataType x)
{assert(php);if (php->size == php->capacity){int newcapacity = php->capacity == 0 ? 4 : 2 * php->capacity;//增容HPDataType* tmp = (HPDataType*)realloc(php->arr, sizeof(HPDataType) * (newcapacity));//增容失败if (tmp == NULL){perror("realloc fail!\n");exit(1);}php->arr = tmp;php->capacity = newcapacity;}php->arr[php->size] = x;//第二个传的参数是php->size,因为下标这个时候最大已经是size,有size+1个数据,我们还没有执行++的操作AdjustUp(php->arr, php->size);++php->size;
}
//判空
bool HPEmpty(HP* php)
{assert(php);return php->size == 0;
}
//向下调整算法
void AdjustDown(HPDataType* arr, int parent, int n)
{int child = parent * 2 + 1;while (child < n){//先找最小的if (child + 1 < n && arr[child] > arr[child + 1]){child++;}if (arr[parent] > arr[child]){Swap(&arr[child], &arr[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}
//删除栈顶数据
void HPpop(HP* php)
{assert(!HPEmpty(php));Swap(&php->arr[0], &php->arr[php->size - 1]);--php->size;AdjustDown(php->arr, 0, php->size);
}
//取堆顶元素
HPDataType HPTop(HP* php)
{assert(!HPEmpty(php));return php->arr[0];
}
//向下调整算法建堆
void HeapSort(HPDataType* arr, int n)
{for (int i = (n - 2) / 2; i >= 0; i--){AdjustDown(arr, i, n);}//堆排序int end = n - 1;while (end > 0){Swap(&arr[0], &arr[end]);AdjustDown(arr, 0, end);end--;}
}
//向上调整算法建堆
void HeapSort01(HPDataType* arr, int n)
{for (int i = 0; i < n; i++){AdjustUp(arr, i);}//堆排序int end = n - 1;while (end > 0){Swap(&arr[0], &arr[end]);AdjustDown(arr, 0, end);end--;}
}
//冒泡排序
void BubbleSort(int* arr, int n)
{for (int i = 0; i < n - 1; i++){int exchange = 0;for (int j = 0; j < n - i - 1; j++){if (arr[j] > arr[j + 1]){exchange = 1;Swap(&arr[j], &arr[j + 1]);}}if (exchange == 0){break;}}
}
typedef int STDataType;
//栈的定义
typedef struct Stack
{STDataType* arr;//所存储的数据int size;//有效数据的个数int capacity;//所能存储的数据个数
}ST;
//栈的初始化
void SLInit(ST* st)
{assert(st);st->arr = NULL;st->size = st->capacity = 0;
}
//入栈
void StackPush(ST* ps, STDataType x)
{assert(ps);if (ps->size == ps->capacity){int newcapacity = ps->capacity == 0 ? 4 : 2 * ps->capacity;STDataType* tmp = (STDataType*)realloc(ps->arr, newcapacity * sizeof(STDataType));//我们这个元素的扩容是在数组上进行操作的,所以我们要这样写if (tmp == NULL){//增容失败perror("realloc fail!\n");exit(1);}ps->arr = tmp;ps->capacity = newcapacity;}ps->arr[ps->size++] = x;
}
//判断栈是否为空
bool StackEmpty(ST* ps)
{assert(ps);return ps->size == 0;//有效数据为0个时,栈就会为空
}
//出栈
void StackPop(ST* ps)
{assert(!StackEmpty(ps));//这个!一定要加上去,如果为true,则栈中没有数据ps->size--;
}
//取栈顶元素
STDataType STTop(ST* ps)
{assert(!StackEmpty(ps));return ps->arr[ps->size - 1];
}
//销毁栈
void STDestroy(ST* ps)
{//如果栈本来就没申请空间,就不需要销毁了//所以我们要加个判断条件if (ps->arr != NULL){//也可以写为ps->capacity!=0或ps->capacityfree(ps->arr);ps->arr = NULL;ps->size = ps->capacity = 0;}
}
bool isValid(char* s)
{ST st;//初始化SLInit(&st);char* pi = s;//用于遍历字符串while (*pi != '\0'){if (*pi == '(' || *pi == '[' || *pi == '{'){//入栈StackPush(&st, *pi);//记得把这个int改为char}else{//判断栈是否为空if (StackEmpty(&st)){//如果为空,直接返回为false//相当于出栈没有了return false;}//可以加个else语句//如果前面条件不成立,直接就跳出了这个函数了//取栈顶元素char top = STTop(&st);//记得出栈,否则之后取的都是一个元素StackPop(&st);//记得pi要解引用,之前我也写错了if ((top == '(' && *pi != ')') || (top == '[' && *pi != ']') || (top == '{' && *pi != '}')){//先返回false的,只有满足所有条件才能返回truereturn false;}}pi++;//记得调整pi,否则会死循环}//如果直接返回的话,就没办法销毁链表bool ret = StackEmpty(&st) ? true : false;//销毁链表STDestroy(&st);return ret;
}
//lomuto前后指针法
int _QuickSort(int* arr, int left, int right)
{int prev = left;int cur = prev + 1;//key也可以不创建,之后又不会发生改变,只是方便理解而已int key = left;while (cur <= right){if (arr[cur] < arr[key] && ++prev != cur){//我们如果把一个位置的数进行交换是没必要的//并且如果把++prev放到前面就会先执行该语句会出错Swap(&arr[cur], &arr[prev]);}++cur;}Swap(&arr[prev], &arr[key]);return prev;
}
快速排序
//void QuickSort(int* arr, int left, int right)
//{
// if (left >= right)
// {
// return;
// }
// //找基准值并进行排序
// int key = _QuickSort(arr, left, right);
// //把数组分为三部分: [left,key-1] key [key+1,right]
// QuickSort(arr, left, key - 1);
// QuickSort(arr, key + 1, right);
//}
// 之前没有在代码中实现这个函数,所以在这里添上
// 取栈顶元素
STDataType StackTop(ST* ps)
{assert(!StackEmpty(ps));return ps->arr[ps->size - 1];
}非递归版本的快速排序
//void QuickSort(int* arr, int left, int right)
//{
// ST st;
// SLInit(&st);
// //先让right和left入栈,防止栈为空
// StackPush(&st, right);
// StackPush(&st, left);
// while (!StackEmpty(&st))
// {
// //取栈顶元素
// int begin = StackTop(&st);
// //要出栈
// StackPop(&st);
// int end = StackTop(&st);
// StackPop(&st);
// //对[begin,end]使用双指针法
// int prev = begin;
// int cur = prev + 1;
// int key = begin;
// while (cur <= end)
// {
// if (arr[cur] < arr[key] && ++prev != cur)
// {
// Swap(&arr[prev], &arr[cur]);
// }
// ++cur;
// }
// Swap(&arr[key], &arr[prev]);
// //记得加上这句话,之前递归的是直接返回了prev,而这里不行,我刚刚也没发现问题
// key = prev;
// //数组分为以下三部分:[begin,prev-1]prev [prev+1,end]
// //先入右子数组
// //从右至左开始入
// if (prev + 1 < end)
// {
// StackPush(&st, end);
// StackPush(&st, prev + 1);
// }
// //再入左子数组
// if (key - 1 > begin)
// {
// StackPush(&st, key - 1);
// StackPush(&st, begin);
// }
// }
// STDestroy(&st);
//}
//自省排序
void IntroSort(int* a, int left, int right, int depth, int defaultDepth)
{if (left >= right){return;}//数组长度小于16的小数组视为插入排序,简单递归次数if (right - left + 1 < 16){InsertSort1(a + left, right - left + 1);return;}//当深度超过2*logN,则改为堆排序if (depth > defaultDepth){HeapSort(a + left, right - left + 1);return;}//其他情况我们直接用上一讲讲过的排序方法depth++;int begin = left;int end = right;//随机选keyint randi = left + (rand() % (right - left));Swap(&a[left], &a[randi]);int prev = left;int cur = prev + 1;int key = left;while (cur <= right){if (a[cur] < a[key] && ++prev != cur){Swap(&a[prev], &a[cur]);}++cur;}Swap(&a[prev], &a[key]);key = prev;//[begin,key-1] [key,key] [key+1,end]IntroSort(a, begin, key - 1, depth, defaultDepth);IntroSort(a, key + 1, end, depth, defaultDepth);
}
//快速排序
void QuickSort(int* a, int left, int right)
{int depth = 0;int logn = 0;int N = right - left + 1;//这个i要从1开始,不然就死循环//我也是找了20分钟才发现的!for (int i = 1; i < N; i *= 2){logn++;}//防止快速排序退化IntroSort(a, left, right, depth, logn * 2);
}
//测试
int main()
{int a[] = { 4,3,8,2,1,9,0,7,6,5 };int n = sizeof(a) / sizeof(a[0]);printf("排序之前: ");for (int i = 0; i < n; i++){printf("%d ", a[i]);}QuickSort(a, 0, n - 1);printf("\n排序之后: ");for (int i = 0; i < n; i++){printf("%d ", a[i]);}return 0;
}
// 测试排序的性能对⽐
void TestOP()
{srand(time(0));const int N = 100000;int* a1 = (int*)malloc(sizeof(int) * N);int* a2 = (int*)malloc(sizeof(int) * N);int* a3 = (int*)malloc(sizeof(int) * N);int* a4 = (int*)malloc(sizeof(int) * N);int* a5 = (int*)malloc(sizeof(int) * N);//int* a6 = (int*)malloc(sizeof(int) * N);int* a7 = (int*)malloc(sizeof(int) * N);for (int i = 0; i < N; ++i){a1[i] = rand();a2[i] = a1[i];a3[i] = a1[i];a4[i] = a1[i];a5[i] = a1[i];//a6[i] = a1[i];a7[i] = a1[i];}int begin1 = clock();InsertSort1(a1, N);int end1 = clock();int begin2 = clock();ShellSort1(a2, N);int end2 = clock();int begin3 = clock();SelectSort1(a3, N);int end3 = clock();int begin4 = clock();HeapSort01(a4, N);int end4 = clock();int begin5 = clock();QuickSort(a5, 0, N - 1);int end5 = clock();//int begin6 = clock();//MergeSort(a6, N);//int end6 = clock();int begin7 = clock();BubbleSort(a7, N);int end7 = clock();printf("InsertSort:%d\n", end1 - begin1);printf("ShellSort:%d\n", end2 - begin2);printf("SelectSort:%d\n", end3 - begin3);printf("HeapSort:%d\n", end4 - begin4);printf("QuickSort:%d\n", end5 - begin5);//printf("MergeSort:%d\n", end6 - begin6);printf("BubbleSort:%d\n", end7 - begin7);free(a1);free(a2);free(a3);free(a4);free(a5);//free(a6);free(a7);
}
//int main()
//{
// TestOP();
//}
运行结果如下:
这个代码是完全复制之前的,所以有些函数是已经没有用处的,至于有些东西和我们排序算法有区别的地方需要自己去理解了,因为这是适用于所有情况的排序算法,太长也很正常,之前的排序总有不适用的情况,需要自己去解决了哦!
相关文章:
*快排延伸-自省排序
此节是学有余力的人去看,如果没时间,不看也没关系,只要知道代码就可以了! 自省排序的思路是自我侦测和反省,快速排序如果递归深度太深,其算法的效率可能被大幅度削弱,这就需要借助其他的算法进…...
三.微服务架构中的精妙设计:服务注册/服务发现-Eureka
一.使用注册中心背景 1.1服务远程调用问题 服务之间远程调⽤时, 我们的URL是写死的 String url "http://127.0.0.1:9090/product/" orderInfo.getProductId(); 缺点: 当更换机器, 或者新增机器时, 这个URL就需要跟着变更, 就需要去通知所有的相关服…...
python-leetcode 63.搜索二维矩阵
题目: 给一个满足两条属性的m*n的整数矩阵: 每行中的整数从左到右按非严格递增顺序排列 每行的第一个整数大于前一行的最后一个整数 给一个整数target,如果target在矩阵中,返回true,否则返回false 方法一:两次二分查找 由于每…...
后端框架入门:Django
Django 基础:模型、视图、模板Django REST Framework 的使用一、Django 概述 Django 是一个 高效、灵活、可扩展 的 Python Web 框架,主要用于快速开发 Web 应用 和 REST API。 📌 Django 的优势: ✅ MTV 架构:模型(Model)、视图(View)、模板(Template)分离,便于…...
从零构建大语言模型全栈开发指南:第四部分:工程实践与部署-4.3.2知识库增强与外部API集成(代码示例:HTTP节点与检索增强生成)
👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 知识库增强与外部API集成:HTTP节点与检索增强生成实战4.3.2 知识库增强与外部API集成(代码示例:HTTP节点与检索增强生成)1. 核心挑战与优化目标1.1 技术瓶颈分析1.2 设计目标2. 关键技术方案2.1 知识…...
音视频入门基础:MPEG2-TS专题(26)——通过FFmpeg命令使用RTP发送TS流
音视频入门基础:MPEG2-TS专题系列文章: 音视频入门基础:MPEG2-TS专题(1)——MPEG2-TS官方文档下载 音视频入门基础:MPEG2-TS专题(2)——使用FFmpeg命令生成ts文件 音视频入门基础…...
blender二次元上色
前: 后:(脸自己会发光) 参考:05-模型导入与材质整理_哔哩哔哩_bilibili...
2025年2月一区SCI-壮丽细尾鹩莺算法Superb Fairy-wren Optimization-附Matlab免费代码
引言 本期介绍一种新的元启发式算法——壮丽细尾鹩莺优化算法Superb Fairy-wren Optimization algorithm,SFOA。该算法结合了壮丽细尾鹩莺群体中幼鸟的发育,繁殖后喂养幼鸟的行为,以及它们躲避捕食者的策略,于2025年2月最新发表在…...
Linux系统禁用swap
Linux系统禁用swap sed -ri s/.*swap.*/#&/ /etc/fstab大家之前禁用swap用上面的命令,也就是把"/etc/fstab"文件里包含swap的那行注释了,然后重启系统swap就被禁用了。 可是到了Ubuntu 20.04之后、CentOS Stream 10、openEuler 24.04、O…...
Hadoop•踩过的SHIT
听说这里是目录哦 ssh登录Permission denied, please try again💩要发癫🥲 centos7 yum报错:cannot find a valid baseurl for repo:base/7/x86_64💩FinalShell重连失效💩ssh免密登录显示 No route to hostὊ…...
闭环SOTA!北航DiffAD:基于扩散模型实现端到端自动驾驶「多任务闭环统一」
端到端自动驾驶目前是有望实现完全自动驾驶的一条有前景的途径。然而,现有的端到端自动驾驶系统通常采用主干网络与多任务头结合的方式,但是它们存在任务协调和系统复杂度高的问题。为此,本文提出了DiffAD,它统一了各种驾驶目标并…...
Docker Registry 清理镜像最佳实践
文章目录 registry-clean1. 简介2. 功能3. 安装 docker4. 配置 docker5. 配置域名解析6. 部署 registry7. Registry API 管理8. 批量清理镜像9. 其他10. 参考registry-clean 1. 简介 registry-clean 是一个强大而高效的解决方案,旨在简化您的 Docker 镜像仓库管理。通过 reg…...
JavaScript重难点突破:期约与异步函数
同步和异步 同步(Synchronous) 定义:任务按顺序依次执行,前一个任务完成前,后续任务必须等待。 特点:阻塞性执行,程序逻辑直观,但效率较低 异步(Asynchron…...
蓝桥杯高频考点——高精度(含C++源码)
高精度 前言高精度加法例题思路及代码solution 1(初阶版 40分)solution 2(完全体 AC) 高精度乘法例题思路及代码solution 1(TLE 但是代码很清晰)solution 1的问题solution 2(优化 AC)…...
(Kotlin) Android使用DialogX实现iOS风格底部弹窗(带Toggle开关)
本文将详细介绍如何使用DialogX库实现一个iOS风格的底部弹窗,包含图标、文本和Toggle开关的列表项。 实现步骤 1. 添加依赖 在build.gradle文件中添加: implementation com.github.kongzue.DialogX:DialogX:0.0.49.beta14 implementation com.github.ko…...
【机器人】复现 GraspNet 端到端抓取点估计 | PyTorch2.3 | CUDA12.1
GraspNet是通用物体抓取的大规模基准的基线模型,值得学习和复现。 本文分享使用较新版本的PyTorch和CUDA,来搭建开发环境。 论文地址:GraspNet-1Billion: A Large-Scale Benchmark for General Object Grasping 开源地址:https:…...
视频联网平台智慧运维系统:智能时代的城市视觉中枢
引言:破解视频运维的"帕累托困境" 在智慧城市与数字化转型浪潮中,全球视频监控设备保有量已突破10亿台,日均产生的视频数据量超过10万PB。然而,传统运维模式正面临三重困境: 海量设备管理失序:…...
《网络管理》实践环节03:snmp服务器上对网络设备和服务器进行初步监控
兰生幽谷,不为莫服而不芳; 君子行义,不为莫知而止休。 应用拓扑图 3.0准备工作 所有Linux服务器上(服务器和Agent端)安装下列工具 yum -y install net-snmp net-snmp-utils 保证所有的HCL网络设备和服务器相互间能…...
ubuntu中使用安卓模拟器
本文这里介绍 使用 android studio Emulator , 当然也有 Anbox (Lightweight), Waydroid (Best for Full Android Experience), 首先确保自己安装了 android studio ; sudo apt update sudo apt install openjdk-11-jdk sudo snap install…...
【Qt】QList<T> list(n)构造函数创建列表时元素 T的默认值
Qt 6支持。 在 Qt 中,当使用 QList<T> list(n); 构造函数创建列表时,元素 T 的默认值取决于其类型的默认构造函数或值初始化规则。以下是常见数据类型的默认值分析: 1. 基本数据类型(POD 类型,Plain Old Data&a…...
py数据结构day3
思维导图: 代码1(完成双向循环链表的判空、尾插、遍历、尾删): class Node:def __init__(self, data):self.data dataself.next Noneself.prev Noneclass DoubleCycleLink:def __init__(self):self.head Noneself.tail None…...
STM32单片机入门学习——第8节: [3-4] 按键控制LED光敏传感器控制蜂鸣器
写这个文章是用来学习的,记录一下我的学习过程。希望我能一直坚持下去,我只是一个小白,只是想好好学习,我知道这会很难,但我还是想去做! 本文写于:2025.04.02 STM32开发板学习——第8节: [3-4] 按键控制LED&光敏传感器控制蜂鸣器 前言开…...
【JavaScript】十三、事件监听与事件类型
文章目录 1、事件监听1.1 案例:击关闭顶部广告1.2 案例:随机点名1.3 事件监听的版本 2、事件类型2.1 鼠标事件2.1.1 语法2.1.2 案例:轮播图主动切换 2.2 焦点事件2.2.1 语法2.2.2 案例:模拟小米搜索框 2.3 键盘事件2.3.1 语法2.3.…...
通过ansible+docker-compose快速安装一主两从redis+三sentinel
目录 示例主机列表 架构参考 文件内容 安装脚本 ansible变量,需修改 ansible配置文件和主机清单,需修改 运行方式 验证故障转移master 涉及redis镜像和完整的脚本文件 示例主机列表 架构参考 文件内容 安装脚本 #!/bin/bashset -e export pa…...
前端和AI怎么高度融合
前端工程师和人工智能(AI)结合可以创造出更加智能和交互式的用户体验。以下是一些前端工程师可以与AI结合的方式: AI聊天机器人:前端工程师可以开发基于AI的聊天机器人,用于与用户交互并提供实时帮助和支持。 个性化推…...
mysql docker容器启动遇到的问题整理
好几个月没折腾mysql的部署,弄了下,又遇到不少问题 问题一:Access denied for user ‘root‘‘172.18.0.1‘ docker容器启动后,本地navicat 连接报这个错误 查到两个方案,一个貌似是要让root用户能在任意ip地址&…...
HTTP keepalive 详解
一、简介 HTTP协议早期版本,比如1.0,默认是不使用持久连接的,也就是每个请求/响应之后都会关闭TCP连接。这样的话,每次请求都需要重新建立连接,增加了延迟和资源消耗。Keep-Alive的作用是保持连接,让多个请…...
长短期记忆神经网络(LSTM)基础学习与实例:预测序列的未来
目录 1. 前言 2. LSTM的基本原理 2.1 LSTM基本结构 2.2 LSTM的计算过程 3. LSTM实例:预测序列的未来 3.1 数据准备 3.2 模型构建 3.3 模型训练 3.4 模型预测 3.5 完整程序预测序列的未来 4. 总结 1. 前言 在深度学习领域,循环神经网络&…...
青少年编程与数学 02-015 大学数学知识点 01课题、概要
青少年编程与数学 02-015 大学数学知识点 01课题、概要 一、线性代数二、概率论与数理统计三、微积分四、优化理论五、离散数学六、数值分析七、信息论 《青少年编程与数学》课程要求,在高中毕业前,尽量完成大部分大学数学知识的学习。一般可以通过线上课…...
C++多继承
可以用多个基类来派生一个类。 格式为: class 类名:类名1,…, 类名n { private: … ; //私有成员说明; public: … ; //公有成员说明; protected: … ; //保护的成员说明; }; class D: public A, protected B, private C { …//派…...
