数据结构排序——计数排序和排序总结(附上912. 排序数组讲解)

2024-01-14 12:36

本文主要是介绍数据结构排序——计数排序和排序总结(附上912. 排序数组讲解),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

数据结构排序——计数排序和排序总结

现在常见算法排序都已讲解完成,今天就再讲个计数排序。再总结一下
请添加图片描述


文章目录

  • 1.计数排序
  • 2.排序总结
  • 3.排序oj(排序数组)
    • 题目详情
    • 代码
    • 思路


1.计数排序

计数排序是一种非基于比较的排序算法,它通过统计数组中每个元素出现的次数,然后根据元素的值和出现次数重新构造数组,从而实现排序。计数排序适用于元素范围比较小元素非负的情况

步骤:

  1. 找出待排序的数组中最大和最小的元素:min和max
  2. 统计数组中每个值为 i 的元素出现的次数,存入新建数组 C 的第 i-min 项(c初始化时都是0),每遇到一次,对应下标上的数就++
  3. 反向填充目标数组:利用新建的数组把数据覆盖回去

时间复杂度:O(n + range)

void CountSort(int* a, int n)
{//先找最大最小,确定范围int max = a[0], min = a[0];for (int i = 1; i < n; i++){if (a[i] > max){max = a[i];}if (a[i] < min){min = a[i];}}int range = max - min + 1;int* count= (int*)calloc(sizeof(int) * range);if (count == NULL){perror("malloc fail");return;}//开始想count中累加了for (int i = 0; i < n; i++){count[a[i] - min]++;}//赋值覆盖int a_index = 0;for (int i = 0; i < range; i++){for (int j = 0; j < count[i]; j++){a[a_index] = i + min;a_index++;}}
}int main()
{int a[] = { 2,4,1,7,9 };CountSort(a, 5);for (int i = 0; i < 5; i++){printf("%d ", a[i]);}return 0;
}

2.排序总结

排序算法时间复杂度空间复杂度稳定性
直接插入排序O(N^2)O(1)稳定
希尔排序O(N^1.3)O(logN)不稳定
选择排序O(N^2)O(N)不稳定
堆排序O(N*logN)O(N)不稳定
冒泡排序O(N^2)O(1)稳定
快速排序O(N*logN)O(logN)不稳定
归并排序O(N*logN)O(N)稳定

不稳定的情况之一:

  1. 希尔:根据gap分组不在一个组
  2. 选择:3 3 1 1…
  3. 堆排序:向下调整过程
  4. 快排:相同的数字其中一个在keyi的位置

3.排序oj(排序数组)

题目详情

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

请添加图片描述

代码

void Swap(int* x, int* y)
{int tmp = *x;*x = *y;*y = tmp;
}int GetMid(int* a,int left, int right)//找中间的
{// a[left]      a[mid]           a[right]int mid = left+(rand()%(right-left));if (a[left] < a[mid]){if (a[mid] < a[right]){return mid;}else if (a[left] > a[right])  // mid是最大值{return left;}else{return right;}}else // a[left] > a[mid]{if (a[left] < a[right]){return left;}else if (a[mid] < a[right]){return right;}else{return mid;}}
}void QuickSort(int* a, int left, int right)
{if (left >= right){return;}int begin = left;int end = right;int mid = GetMid(a, left, right);Swap(&a[mid], &a[left]);int cur = left + 1;int key = a[left];//储存一下,后面比较来用,用a[left]会被替代while (cur <= right){if (a[cur] < key){Swap(&a[cur], &a[left]);cur++;left++;}else if (a[cur] == key){cur++;}else{Swap(&a[cur], &a[right]);right--;}}QuickSort(a, begin, left - 1);QuickSort(a, right + 1, end);
}int* sortArray(int* nums, int numsSize, int* returnSize) {srand(time(0));QuickSort(nums,0,numsSize-1);*returnSize=numsSize;return nums;
}

请添加图片描述

  1. Swap函数: 这是一个用于交换两个整数值的简单函数。
  2. GetMid函数: 用于在数组中找到三个位置(左、中、右)的元素,从而选取合适的中间值。它通过比较这三个位置的元素,找到其中介于最小和最大之间的值。
  3. QuickSort函数:实现了快速排序的核心逻辑
    • 选择中间值,并将其与数组的第一个元素交换,作为基准值。
    • 遍历数组,将小于基准值的元素移到基准值左侧,大于基准值的元素移到右侧,相等的元素留在中间。
    • 对基准值左右两侧的子数组递归地进行快速排序,直到左右两侧都排好序

思路

这题有根据快排的痛点进行特地进行测试用例的编写

一开始大家肯定就直接放上去一个快排,结果发现:超时了(过不去的测试用例是有序的)

  • 所以第一次我们要加上三选一
  • 发现还不行(过不去的是数字全部一样),现在就考虑换上三路划分
  • 最后发现测试用例可以,但是时间过长,就改一下Getmid函数,之前mid ( l e f t + r i g h t ) / 2 (left+right)/2 (left+right)/2,现在是left+(rand()%(right-left))

好啦,排序的内容也到这里啦。下面就要开启c++的内容了

这篇关于数据结构排序——计数排序和排序总结(附上912. 排序数组讲解)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/605176

相关文章

C#数据结构之字符串(string)详解

《C#数据结构之字符串(string)详解》:本文主要介绍C#数据结构之字符串(string),具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录转义字符序列字符串的创建字符串的声明null字符串与空字符串重复单字符字符串的构造字符串的属性和常用方法属性常用方法总结摘

C# WinForms存储过程操作数据库的实例讲解

《C#WinForms存储过程操作数据库的实例讲解》:本文主要介绍C#WinForms存储过程操作数据库的实例,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、存储过程基础二、C# 调用流程1. 数据库连接配置2. 执行存储过程(增删改)3. 查询数据三、事务处

java常见报错及解决方案总结

《java常见报错及解决方案总结》:本文主要介绍Java编程中常见错误类型及示例,包括语法错误、空指针异常、数组下标越界、类型转换异常、文件未找到异常、除以零异常、非法线程操作异常、方法未定义异常... 目录1. 语法错误 (Syntax Errors)示例 1:解决方案:2. 空指针异常 (NullPoi

C++原地删除有序数组重复项的N种方法

《C++原地删除有序数组重复项的N种方法》给定一个排序数组,你需要在原地删除重复出现的元素,使得每个元素只出现一次,返回移除后数组的新长度,不要使用额外的数组空间,你必须在原地修改输入数组并在使用O(... 目录一、问题二、问题分析三、算法实现四、问题变体:最多保留两次五、分析和代码实现5.1、问题分析5.

C++快速排序超详细讲解

《C++快速排序超详细讲解》快速排序是一种高效的排序算法,通过分治法将数组划分为两部分,递归排序,直到整个数组有序,通过代码解析和示例,详细解释了快速排序的工作原理和实现过程,需要的朋友可以参考下... 目录一、快速排序原理二、快速排序标准代码三、代码解析四、使用while循环的快速排序1.代码代码1.由快

Java反转字符串的五种方法总结

《Java反转字符串的五种方法总结》:本文主要介绍五种在Java中反转字符串的方法,包括使用StringBuilder的reverse()方法、字符数组、自定义StringBuilder方法、直接... 目录前言方法一:使用StringBuilder的reverse()方法方法二:使用字符数组方法三:使用自

Java中数组转换为列表的两种实现方式(超简单)

《Java中数组转换为列表的两种实现方式(超简单)》本文介绍了在Java中将数组转换为列表的两种常见方法使用Arrays.asList和Java8的StreamAPI,Arrays.asList方法简... 目录1. 使用Java Collections框架(Arrays.asList)1.1 示例代码1.

Python依赖库的几种离线安装方法总结

《Python依赖库的几种离线安装方法总结》:本文主要介绍如何在Python中使用pip工具进行依赖库的安装和管理,包括如何导出和导入依赖包列表、如何下载和安装单个或多个库包及其依赖,以及如何指定... 目录前言一、如何copy一个python环境二、如何下载一个包及其依赖并安装三、如何导出requirem

Rust格式化输出方式总结

《Rust格式化输出方式总结》Rust提供了强大的格式化输出功能,通过std::fmt模块和相关的宏来实现,主要的输出宏包括println!和format!,它们支持多种格式化占位符,如{}、{:?}... 目录Rust格式化输出方式基本的格式化输出格式化占位符Format 特性总结Rust格式化输出方式

Java集合中的List超详细讲解

《Java集合中的List超详细讲解》本文详细介绍了Java集合框架中的List接口,包括其在集合中的位置、继承体系、常用操作和代码示例,以及不同实现类(如ArrayList、LinkedList和V... 目录一,List的继承体系二,List的常用操作及代码示例1,创建List实例2,增加元素3,访问元