快速排序的非递归实现、归并排序的递归和非递归实现、基数排序、排序算法的时间复杂度

文章目录

  • 快速排序的非递归
    • 三数取中法选取key
    • 快速排序三路划分
  • 归并排序的递归
  • 归并排序的非递归
  • 计数排序
  • 稳定性
  • 排序算法的时间复杂度

快速排序的非递归

我们使用一个栈来模拟函数的递归过程,这里就是在利用栈分区间。把一个区间分为 [left,keyi-1][key][keyi+1,right]递归下去,直至区间不存在或left > right。
如图所示:
在这里插入图片描述
先把整体的区间压进去,然后出栈,处理完毕后找到keyi再分为左右两个区间。然后往栈里压有区间,压左区间,就像树的后续遍历一样先把叶子区间处理,再处理分支节点的区间。
代码如下所示:

void QuickSortNonS(int* a, int left, int right)
{ST st;STInit(&st);STPush(&st, left);STPush(&st, right);while (!STEmpty(&st)){int right = STTop(&st);STPop(&st);int left = STTop(&st);STPop(&st);int keyi = PastSort1(a, left, right);//先入右区间if (keyi + 1 < right){STPush(&st, keyi + 1);STPush(&st, right);}//再入左区间if (keyi - 1 > left){STPush(&st, left);STPush(&st, keyi - 1);}}STDestory(&st);
}

三数取中法选取key

还可以选择三数取中法来选取key的值,原理是选取不大不小的数使得快速排序的交换次数变少。
代码如下:

//三数取中法选取Key
int GetMidKey(int* a, int left, int right)
{int mid = (left + right) / 2;if (a[left] <= a[right]&&a[left] <= a[mid] && a[mid] <= a[right]){return mid;}else if(a[left]<=a[mid]&&a[left]<=a[right]&&a[left]<=a[mid]){return right;}else if (a[right]<=a[mid]&&a[right]<=a[left]&&a[left]<=a[mid]){return left;}else if (a[mid] <= a[left] && a[mid] <= a[right] && a[right] <= a[left]){return right;}else if (a[mid] <= a[right] && a[mid] <= a[left] && a[left] <= a[right]){return left;}else if (a[right] <= a[left] && a[right] <= a[mid] && a[mid] <= a[left]){return mid;}else{return left;}
}

快速排序三路划分

原理:规定左指针,cur指针,右指针。当a[cur] < key时,把a[cur]和a[left]的值交换cur++,left++。当a[cur] > key时,把a[cur]和a[right]的值交换,right–。当a[cur] > key时,cur++,具体的操作过程如下图所示:
在这里插入图片描述
代码如下:

//三路划分
//1、最小的在最左边
//2、最大的在最右边
//3、相等的在中间void QuickSort1(int* a, int begin, int end)
{if (begin > end){return;}//三路划分int keyi = GetMidKey(a, begin, end);Swap(&a[begin], &a[keyi]);int key = a[begin];int left = begin;int right = end;int cur = left + 1;while (cur <= right){if (a[cur] < key){Swap(&a[cur], &a[left]);left++;cur++;}else if (a[cur] > key){Swap(&a[cur], &a[right]);right--;}else{cur++;}}//[begin,left-1][left,right][right+1,end]QuickSort(a, begin, left-1);QuickSort(a, right + 1, end);
}

归并排序的递归

基本思想:
归并排序(MERGE-SORT)是建立在归并操作上的一种有效的排序算法,该算法是采用分治法(Divide andConquer)的一个非常典型的应用。将已有序的子序列合并,得到完全有序的序列;即先使每个子序列有序,再使子序列段间有序。若将两个有序表合并成一个有序表,称为二路归并。 归并排序核心步骤:
在这里插入图片描述
递归代码如下所示:

void _MergeSort(int* a, int begin, int end, int* temp)
{//递归结束条件if (begin >= end){return;}//我们需要分区间进行,把区间可以分为//[begin,mid][mid+1,end]int mid = (begin + end) / 2;//通过后序遍历使得最小的区间有序[0,0][1,1][2,2]……[end-1,end-1][end,end]_MergeSort(a, begin, mid, temp);_MergeSort(a, mid+1, end, temp);//开始处理归并排序,也就是处理二叉树根的排序问题 左右根//这里相当于合并两个有序数组int begin1 = begin, end1 = mid;int begin2 = mid + 1, end2 = end;int i = begin;while (begin1<=end1&&begin2<=end2){if (a[begin1] < a[begin2]){temp[i++] = a[begin1++];}else{temp[i++] = a[begin2++];}}while (begin1 <= end1){temp[i++] = a[begin1++];}while (begin2 <= end2){temp[i++] = a[begin2++];}//再把数据拷回去memcpy(a+begin, temp+begin,sizeof(int)*(end-begin+1));
}//归并排序递归算法
void MergeSort(int* a, int n)
{//我们需要开辟一个数组int* temp = (int*)malloc(sizeof(int) * n);//进行递归需要一个子函数_MergeSort(a, 0, n - 1, temp);free(temp);
}

递归展开图:
在这里插入图片描述

归并排序的非递归

原理:如下图所示:
在这里插入图片描述
划分为一个数一个数一组归并排序后再划分为两个数一组,然后再归并直至数组有序
代码如下:

//归并排序非递归
void MergeSortNonS(int* a, int n)
{int gap = 1;int* temp = (int*)malloc(sizeof(int) * n);while (gap < n){int j = 0;for (int i = 0; i < n; i += gap * 2){//第一趟归并排序1数据归并成两个数,//第二趟2个数归为4个数//第三趟4个数,4和4归并成8个数int begin1 = i, end1 = i + gap - 1;int begin2 = i + gap, end2 = i + gap * 2 - 1;//一块一块进行拷贝/*if (end1 >= n || begin2 >= n){break;}if (end2 >= n){end2 = n - 1;}*///直接修正if (end1 >= n){end1 = n - 1;//不存在的区间begin2 = n;end2 = n-1;}else if (end2 >= n){end2 = n - 1;}else if (begin2 >= n ){begin2 = n;end2 = n - 1;}printf("[%d %d][%d %d]\n", begin1, end1, begin2, end2);while (begin1 <= end1 && begin2 <= end2){if (a[begin1] < a[begin2]){temp[j++] = a[begin1++];}else{temp[j++] = a[begin2++];}}while (begin1 <= end1){temp[j++] = a[begin1++];}while (begin2 <= end2){temp[j++] = a[begin2++];}//一块一块进行拷贝//memcpy(a+i, temp+i, sizeof(int)*(end2-i)+1);}//直接拷贝memcpy(a, temp, sizeof(int) * n);gap *= 2;}free(temp);
}

这里需要注意溢出的三种情况
在这里插入图片描述
消除溢出的方法有两种,均已在代码注释中标出。

计数排序

计数排序应用了相对映射的方法
如下图所示:
在这里插入图片描述
代码实现:

//计数排序
void CountSort(int* a, int n)
{//首先找出最大值和最小值int max = a[0];int min = a[0];//相对映射for (int i = 0; i < n; i++){if (max < a[i]){max = a[i];}if (min > a[i]){min = a[i];}}//求出范围int range = max - min;//开辟一个range大小的数组int* temp = (int*)malloc(sizeof(int) * range+1);for (int i = 0; i < n;i++){temp[i] = 0;}//统计次数for (int i = 0; i < n; i++){temp[a[i] - min]++;}//排序for (int i = 0; i < n; i++){while (temp[i]--){a[i] = i + min;}}free(temp);
}

稳定性

稳定的排序算法:冒泡排序,计数排序,归并排序,直接插入排序。
不稳定的排序算法 :堆排序,快速排序,选择排序,希尔排序。

排序算法的时间复杂度

基数排序
时间复杂度O(N+范围)
空间复杂度O(范围)

在这里插入图片描述

数据结构的初阶到此为止,高阶数据结构将用C++来描述。

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

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

相关文章

TypeScript 学习笔记 环境安装-类型注解-语法细节-类-接口-泛型

文章目录 TypeScript 学习笔记概述TypeScript 开发环境搭建 类型注解类型推断 数据类型JS的7个原始类型Array数组object、Object 和 {}可选属性 ? 和 可选链运算符?. function函数TS类型: any类型 | unknow类型TS类型: void类型TS类型&#xff1a;never类型 &#xff08;几乎…

Signal-iOS 5.9.0编译问题

1.当我们使用pod管理 pod SDWebImage/WebP , 执行 pod install 时,发生报错.先看具体报错 : 截屏2020-07-06 上午11.12.15.png 2.报错产生原因是由于git clone 的地址是 https://chromium.googlesource.com/webm/libwebp,需要FQ 3.不想FQ,可以使用github上的地址https://githu…

vue upload 下载

目录 上传 下载 get post 对象/文件流 download处理返回 文件流 axios.post 封装axios 后端直接返回文件流&#xff0c;打开下载文件是 [object Object]&#xff0c;将res改成res.data即可 1.请求设置类型responseType: blob&#xff08;如果没有设置&#xff0c;打…

蓝牙技术|低功耗蓝牙和LE Audio助力游戏设备行业发展

去年&#xff0c;蓝牙技术联盟官方宣布推出LE Audio&#xff0c;它以BLE为基础&#xff0c;旨在更好地兼顾音频质量和低功耗&#xff0c;以在多种潜在应用中显著增强用户体验。这在游戏行业中引起了轰动&#xff0c;由于其延迟显著降低&#xff0c;LE Audio在增强游戏体验方面展…

【计算机视觉 | 目标检测 | 图像分割】arxiv 计算机视觉关于目标检测和图像分割的学术速递(7 月 14 日论文合集)

文章目录 一、检测相关(6篇)1.1 LVLane: Deep Learning for Lane Detection and Classification in Challenging Conditions1.2 Garbage in, garbage out: Zero-shot detection of crime using Large Language Models1.3 Robotic surface exploration with vision and tactile …

asp.net core框架搭建1-搭建webapi,对数据增删改查接口模板(附源码)

文章目录 系列文章1.项目搭建1.1 新建Asp.net core webapi项目1.2 配置连接Mysql1.3 实现对mysql数据库的数据增删改查&#xff0c;接口1.3.1 根据id查询数据1.3.2 根据用户名模糊查询数据&#xff0c;并分页1.3.3 新增用户数据1.3.4 修改用户数据1.3.5 根据ID删除数据1.3.6 接…

【5G PHY】5G 调制与编码策略(MCS)介绍

博主未授权任何人或组织机构转载博主任何原创文章&#xff0c;感谢各位对原创的支持&#xff01; 博主链接 本人就职于国际知名终端厂商&#xff0c;负责modem芯片研发。 在5G早期负责终端数据业务层、核心网相关的开发工作&#xff0c;目前牵头6G算力网络技术标准研究。 博客…

Redis对象结构 — RedisObject

目录 Redis 键值对数据库的全过程​编辑 RedisObject结构体 Redis的encoding编码方式 type对应的数据对象类型 Redis 键值对数据库的全过程 redisDb 结构&#xff0c;表示 Redis 数据库的结构&#xff0c;结构体里存放了指向了 dict 结构的指针&#xff1b;dict 结构&#…

Day_63-65 集成学习之 AdaBoosting

目录 Day_63-65 一. 基本概念介绍 1. 集成学习 2. 弱分类器与强分类器 二. AdaBoosting算法 1. AdaBoosting算法框架介绍 2. AdaBoosting算法过程 三. 代码的实现过程 1. WeightedInstances类 2. 构造弱分类器的StumpClassifier类和抽象类SimpleClassifier 3. 主类Booster的…

Unity 之 超级详细的隐私问题解决方案

Unity 之 助力游戏增长 -- 解决隐私问题 一&#xff0c;平台测试隐私问题二&#xff0c;解决方式一2.1 勾选自定义Mainifest2.2 修改自定义Mainifest2.3 隐私协议弹窗逻辑 三&#xff0c;解决方式二3.1 导出安卓工程3.2 创建上层Activity3.3 配置AndroidManifest 四&#xff0…

小红书Java后端一面,被问麻了

今天分享一篇小红书 2 年社招 Java 后端一面的面经&#xff0c;面试的风格是从一个知识一层一层深入问到底层。 从 Java IO&#xff0c;问到 socket 底层。从 Java 内存&#xff0c;问到操作系统内存。所以学习知识的时候&#xff0c;不要只看八股文&#xff0c;还是需要从点到…

集群基础3——haproxy负载均衡apache

文章目录 一、环境说明二、安装配置httpd三、安装配置haproxy四、验证http负载均衡五、配置https负载均衡六、haproxy网页监控6.1 监控参数详解6.2 页面操作 一、环境说明 使用haproxy对apache进行负载均衡。 主机IP角色安装服务192.168.161.131后端服务器1httpd,80端口192.168…