news 2026/4/2 18:18:11

C++选择排序插入排序希尔排序快排归并排及大小根堆实现优先级队列

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++选择排序插入排序希尔排序快排归并排及大小根堆实现优先级队列

1.选择排序

(1)选择排序的实现

void ChoiceSort(int arr[], int size) { for (int i = 0; i < size - 1; i++) { int min = arr[i]; int k = i; // 记录最小值下标 for (int j = 1 + i; j < size; j++) { if (arr[j] < min) { k = j; min = arr[j]; } } if (k != i) { int tmp = arr[i]; arr[i] = arr[k]; arr[k] = tmp; } } }

这里k用来记录最小值的下标。

(2)相关知识

特点:每次选取元素中的最小值与当前元素进行交换。

缺点:相比冒泡排序交换的次数减少了,但是比较的次数仍然很多。

选择排序的平均时间复杂度是O(n*n),最好时间复杂度是O(n*n),最坏时间复杂度是O(n*n),空间复杂度O(1),稳定性(不稳定)

2.插入排序

(1)插入排序的实现

void InsertSort(int arr[], int size) { for (int i = 1; i < size; i++) { int val = arr[i]; int j = i - 1; for (; j >= 0; j--) { if (arr[j] <= val) { break; } arr[j + 1] = arr[j]; } arr[j + 1] = val; } }

(2)相关知识

特点:从第二个元素开始把前面的序列当成有序的,然后找到合适的位置进行插入。

优点:插入排序是普通排序里面效率最高的,在数据本身趋于有序的情况下插入排序是所有排序算法中效率最高的。

插入排序的平均时间复杂度O(n*n),最好时间复杂度O(n),最坏时间复杂度O(n*n),空间复杂度O(1),稳定性(稳定)

3.希尔排序

(1)希尔排序的实现

void ShellSort(int arr[], int size) { for (int gap = size; gap > 0; gap /= 2) { for (int i = gap; i < size; i++) { int val = arr[i]; int j = i - gap; for (; j >= 0; j-=gap) { if (arr[j] <= val) { break; } arr[j + gap] = arr[j]; } arr[j + gap] = val; } } }

(2)相关知识

特点:可以看作是多路的插入排序,每组的序列逐渐趋于有序,整体的序列也逐渐趋于有序,插入排序的完美体现。

希尔排序的平均时间复杂度O(n^1.3),最好时间复杂度O(n),最坏时间复杂度O(n*n),空间复杂度O(1),稳定性(不稳定)

4.快速排序

(1)快速排序的实现

//快排分割处理函数 int PartAction(int arr[],int l,int r) { //确定基准值 int val = arr[l]; //分割处理 while(l < r) { //r从右边找到第一个小于等于val的值放到l的位置,l++ while(l < r && arr[r] > val) { r --; } if(l < r) { arr[l] = arr[r]; l++; } //l从左边找到一个大于等于val的值放到r的位置上,r-- while(l < r && arr[l] < val) { l ++; } if(l < r) { arr[r] = arr[l]; r--; } } arr[l] = val; return l; } //快速排序的递归接口 void QuickSort(int arr[],int begin,int end) { //递归结束条件 if(begin >= end) { return ; } //快排分割函数 int pos = PartAction(arr,begin,end); //基准数的左边和右边再进行快排处理 QuickSort(arr,begin,pos-1); QuickSort(arr,pos+1,end); } //快速排序的递归实现 void QuickSort(int arr[],int size) { QuickSort(arr,0,size-1); }

(2)相关知识

特点:选取基准数,将小于基准数的值放到基准数的左边,大于基准数的放到基准数的右边,采用“分治思想”处理剩余的序列元素直到整个序列变成有序序列。

优化点:1.结合插入排序,当序列数据量小于某个值是采用插入排序进行排序。

2.采用”三数取中法”来进行基准数的选取。

3.随机数取基准数法

快速排序的平均时间复杂度为O(nlogn),最坏时间复杂度O(n*n),最好时间复杂度O(nlogn),空间复杂符O(logn)到O(n).稳定性(不稳定)。

5.归并排序

(1)归并排序的实现

//归并排序的排序接口 void Merge(int arr[],int l,int m,int r) { int *p = new int[r-l+1]; int pi = 0; int i = l; int j = m+1; while(i <= m && j <= r) { if(arr[i] <= arr[j]) { p[pi++] = arr[i++]; } else { p[pi++] = arr[j++]; } } while(i <= m) { p[pi++] = arr[i++]; } while(j <= r) { p[pi++] = arr[j++]; } for(i=l,j=0;i<=r;i++,j++) { arr[i] = p[j]; } delete p; } //归并排序的递归接口 void MergeSort(int arr[],int begin,int end) { //递归的结束条件 if(begin >= end) { return ; } //讲数组划分再进行递 int mid = (begin + end)/2; MergeSort(arr,begin,mid); MergeSort(arr,mid+1,end); //在归的过程中进行排序,将两个小段有序数组合成一个大段有序数组 Merge(arr,begin,mid,end); } //归并排序的实现 void MergeSort(int arr[],int size) { MergeSort(arr,0,size-1); }

(2)相关知识

特点:采用“分治思想”,先将序列进行划分,再进行合并排序

归并排序的平均时间复杂度O(nlogn),最坏时间复杂度O(nlogn),最好时间复杂度O(nlogn),空间复杂度O(n),稳定性(稳定)。

6.大小根堆优先级队列

(1)大小根堆优先级队列的实现

class PriorityQueue { public: using Comp = function<bool(int,int)>; PriorityQueue(int cap = 20,Comp comp = greater<int>()) :size_(0) ,cap_(cap) ,comp_(comp) { que_ = new int[cap_]; } PriorityQueue(Comp comp) :comp_(comp) ,cap_(20) ,size_(0) { que_ = new int[cap_]; } ~PriorityQueue() { delete []que_; que_ = nullptr; } //入堆 void push(int val) { if(size_ == cap_) { int *p = new int[cap_*2]; memcpy(p,que_,size_*sizeof(int)); delete []que_; que_ = p; cap_ *= 2; } if(size_ == 0) { que_[size_] = val; } else { //进行入堆上浮操作 siftUp(size_,val); } size_ ++; } //出堆 void pop() { if(size_ == 0) { throw "PriorityQueue is empty"; } size_ --; if(size_ == 0) { return; } else { //进行一个出堆下沉操作 siftDown(0,size_); } } //获取堆顶元素 int top() { if(size_ == 0) { throw "PriorityQueue is empty!"; } return que_[0]; } //判空 bool empty() { return size_ == 0; } //获取有效元素个数 int size() { return size_; } private: //入堆上浮操作 void siftUp(int i,int val) { while(i > 0) { //与当前父节点进行大小对比 int father = (i-1)/2; if(comp_(val,que_[father])) //注意与父节点比较的值是当前要入堆的值 { que_[i] = que_[father]; i = father; } else { break; } } que_[i] = val; } //出堆下沉操作 void siftDown(int i,int size) { while(i <= (size-2)/2) { int child = 2*i+1; if(child+1<size_ && comp_(que_[child+1],que_[child])) { child = child +1; } if(comp_(que_[child],que_[size])) { que_[i] = que_[child]; i = child; } else { break; } } que_[i] = que_[size]; } int *que_; int size_; int cap_; Comp comp_; };

在进行入堆的上浮和出堆的下沉操作时,对于和父子节点比较的值一个是要入堆的值,一个是数组最后一个元素的值。

(2)相关知识

大根堆特点:有子节点的父节点,父节点的值会大于子节点

小根堆特点:有子节点的父节点,父节点的值小于子节点

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/3/11 22:18:33

驱动程序初学者指南:字符设备注册全过程

从零开始写一个字符设备驱动&#xff1a;手把手带你走进内核开发大门你有没有试过在 Linux 系统中读写/dev目录下的某个设备文件&#xff1f;比如用echo "hello" > /dev/ttyS0向串口发数据&#xff0c;或者通过/dev/input/event0获取键盘输入。这些看似普通的“文…

作者头像 李华
网站建设 2026/3/3 6:27:08

RS485通讯结合Modbus的手把手教程

从零构建工业通信链路&#xff1a;RS485 Modbus实战全解析在工厂车间的PLC柜里&#xff0c;一根双绞线串联起十几台设备&#xff1b;在楼宇自控系统中&#xff0c;温湿度传感器通过一条总线将数据传回中央控制器——这些看似简单的连接背后&#xff0c;往往运行着一个历经四十…

作者头像 李华
网站建设 2026/3/27 22:39:57

GitHub Projects管理PyTorch功能迭代开发进度

GitHub Projects 与 PyTorch-CUDA 容器化开发的协同实践 在人工智能项目日益复杂、团队协作频繁的今天&#xff0c;一个常见的困境是&#xff1a;代码能跑&#xff0c;但换台机器就“不可复现”&#xff1b;任务在推进&#xff0c;但进度却“看不见摸不着”。尤其是在基于 PyTo…

作者头像 李华
网站建设 2026/3/27 11:51:39

基于OpenMV识别物体的智能门禁系统设计:完整指南

用 OpenMV 做一个“看脸”&#xff08;其实是看卡&#xff09;的智能门禁&#xff1a;从零搭建全过程你有没有想过&#xff0c;自家门口那扇老式铁门&#xff0c;也能变得像科幻电影里一样——人还没靠近&#xff0c;锁就自动开了&#xff1f;当然&#xff0c;我们不是真的靠“…

作者头像 李华
网站建设 2026/4/1 3:53:37

Git stash暂存未完成修改切换PyTorch开发上下文

Git stash暂存未完成修改切换PyTorch开发上下文 在现代AI工程实践中&#xff0c;开发者常常面临一个看似简单却极易引发问题的场景&#xff1a;你正全神贯注地调试一个复杂的注意力模块&#xff0c;代码改到一半&#xff0c;train.py 里还躺着几处未提交的实验性改动。突然&…

作者头像 李华
网站建设 2026/3/19 17:20:27

Markdown表格对比不同PyTorch版本特性差异

PyTorch-CUDA 镜像深度解析&#xff1a;从版本差异到工程实践 在深度学习项目快速迭代的今天&#xff0c;一个常见的场景是&#xff1a;新成员加入团队后&#xff0c;第一项任务不是写代码&#xff0c;而是花上几个小时甚至一整天来“配环境”——安装 CUDA、匹配 cuDNN 版本、…

作者头像 李华