912. Sort an Array排序复习 快速排序,选择排序,插入排序,归并排序,堆排序

本文主要是介绍912. Sort an Array排序复习 快速排序,选择排序,插入排序,归并排序,堆排序,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

快速排序

选择排序 

插入排序

归并排序

堆排序

总结


Given an array of integers nums, sort the array in ascending order.

Example 1:

Input: nums = [5,2,3,1]
Output: [1,2,3,5]

Example 2:

Input: nums = [5,1,1,2,0,0]
Output: [0,0,1,1,2,5]

Constraints:

  • 1 <= nums.length <= 50000
  • -50000 <= nums[i] <= 50000

题目链接: Loading...

快速排序

class Solution {
public:void quicksort(vector<int>&nums,int left,int right){if(left>=right)//此处应该是大于等于,等于的时候就可以停止了{return ;}int i=left,j=right,key=nums[left];while(i<j){while(i<j&&nums[j]>=key){//选出来的nums[j] 小于 keyj--;}nums[i]=nums[j];while(i<j&&nums[i]<=key)//选出来的nums[i] 大于 key{i++;}nums[j]=nums[i];}nums[i]=key;quicksort(nums,left,i-1);quicksort(nums,i+1,right);}vector<int> sortArray(vector<int>& nums) {quicksort(nums,0,nums.size()-1);return nums;}
};

快速排序是不稳定的,为什么呢?

经过第一次sort后,对于j,j=5就停止了,对于i,i一直++到5。

这样赋值后,红色的9跑到黑色的9后面了。 

有的例子就刚好不会变,下面这种就不会变化。

选择排序 

是想复习一下,但是选择排序复杂度比较高,过不了。这些排序的复杂度表

void selectSort(vector<int>&nums){int len=nums.size();int index=0;for(int i=0;i<len;i++){index=i;for(int j=i+1;j<len;j++){if(nums[j]<nums[index]){index=j;}}int tmp=nums[i];nums[i]=nums[index];nums[index]=tmp;}}

插入排序

也是超时,原理很简单,在从小到大的排序方法中,就是  左边有序序列,新来一个值newvalue,就和左边有序序列比较,只要比我,我就往右边挪位置,nums[j+1]=nums[j]。

void insertSort(vector<int>& nums){int len=nums.size(),tmp=0,i=0,j=0;for(i=1;i<len;i++){tmp=nums[i];for(j=i-1;j>=0&&tmp<nums[j];j--){nums[j+1]=nums[j];//nums[j]小于 tmp,往后挪位置}nums[j+1]=tmp;//j退出时候,要么j=-1,或者 nums[j]< tmp,那你tmp只能放在 j+1的位置上}}

归并排序

这道题在归并排序上真是给我好好上了一课,之前写的归并排序没有问题,但是有一些额外的空间浪费和时间开销。就是我全行注释那行,如果每次都是按照nums的真实长度来初始化tmp,会浪费时间和空间,这题LeetCode会超时。刚开始我百思不得其解,后来发现是这个问题,真是学习了。我之前写的归并代码:随手写写之归并排序

    void mergeArray(vector<int>& nums,int start,int mid,int last){vector<int> tmp(last-start+1,0);// vector<int> tmp(nums.size(),0);这一点真的很棒,考虑数组元素多的时候,这样初始化很浪费时间,会超时,这点leetcode给我上了一课。int i=start,j=mid+1,k=0;//k记录start位置,tmp从哪个下标开始while(i<=mid&&j<=last){if(nums[i]<nums[j]){tmp[k++]=nums[i++];}else{tmp[k++]=nums[j++];}}while(i<=mid){tmp[k++]=nums[i++];}while(j<=last){tmp[k++]=nums[j++];}for(int t=start;t<=last;t++){nums[t]=tmp[t-start];}}void mergeSort(vector<int>& nums,int start,int last){if(start<last){int mid=(start+last)/2;mergeSort(nums,start,mid);mergeSort(nums,mid+1,last);mergeArray(nums,start,mid,last);}}

  

堆排序

堆排序(这篇博客说的挺好的排序六 堆排序)是使用大根堆(父节点不小于子节点,为啥从下往上调整呢,看个例子

把3和1调完之后, 根节点还要调整(因为4是最大的,4还要和根节点调整,导致根节点的值换了2次,从下往上调整,根节点只需要调整一次就行了,这样从下往上调整,所有非叶子节点调整一次,绝对就是对的了,不用考虑有的节点是不是还要调整一次),一个节点就可能重复调整,不止一次。从下往上调整,省去了父节点二次调整,简单省事了,不用考虑二次调整了。

这个例子第一次的调整构造初始堆过程如下图:

上面这个例子层数有点少,2种遍历都是调整3次,但是对于一个节点,既是父节点又是子节点,它的子节点还有子节点 ,步骤就上来了,比如下图的数字4

void heapAdjust(vector <int> & arr, int parent,int N){int largest = parent;int child=2*parent+1;while(child<N)//N代表整个数组的元素个数,下标从0开始,child必须小于N{if(arr[child]>arr[largest]){largest=child;}if(child+1<N&&arr[child+1]>arr[largest]){largest=child+1;child++;//更新child的值}swap(arr[parent],arr[largest]);//交换parent=largest;// parent=child;在没有child大于parent的时候,largest还是parent,child是2*parent+1,所以不能这么写child=2*child+1;//child根据child值翻倍,这样如果么有需要更新的,parent一直不变,child一直增大会退出}}void heapSort(vector<int>& nums){for(int i = nums.size()/2; i >= 0; i--){//从最后一个非叶子节点开始调整heapAdjust(nums,i,nums.size());}for(int i = nums.size()-1; i >= 0; i--){swap(nums[0] , nums[i]);//下标0存放的是调整后最大值,交换后放到下标 i(当前未排序的最后位置)heapAdjust(nums,0,i);//i表示调整的元素个数,i从 size()-1  开始}}

堆排序是不稳定的,看个图,原先的数组顺序是 1 2 2,调整之后 1 2 2,黄框是排序一次后的堆结构。

 

总结

对于这道题,我把所有排序方法都汇总在一起了

class Solution {
public:
void quickSort(vector<int>&nums,int left,int right){if(left>right){return ;}int i=left,j=right,key=nums[left];while(i<j){while(i<j&&nums[j]>=key){//选出来的nums[j] 小于 keyj--;}nums[i]=nums[j];while(i<j&&nums[i]<=key)//选出来的nums[i] 大于 key{i++;}nums[j]=nums[i];}nums[i]=key;quickSort(nums,left,i-1);quickSort(nums,i+1,right);}void selectSort(vector<int>&nums){int len=nums.size();int index=0;for(int i=0;i<len;i++){index=i;for(int j=i+1;j<len;j++){if(nums[j]<nums[index]){index=j;}}int tmp=nums[i];nums[i]=nums[index];nums[index]=tmp;}}void insertSort(vector<int>& nums){int len=nums.size(),tmp=0,i=0,j=0;for(i=1;i<len;i++){tmp=nums[i];for(j=i-1;j>=0&&tmp<nums[j];j--){nums[j+1]=nums[j];//nums[j]小于 tmp,往后挪位置}nums[j+1]=tmp;//j退出时候,要么j=-1,或者 nums[j]< tmp,那你tmp只能放在 j+1的位置上}}void mergeArray(vector<int>& nums,int start,int mid,int last){vector<int> tmp(last-start+1,0);// vector<int> tmp(nums.size(),0);这一点真的很棒,考虑数组元素多的时候,这样初始化很浪费时间,会超时,这点leetcode给我上了一课。int i=start,j=mid+1,k=0;//k记录start位置,tmp从哪个下标开始while(i<=mid&&j<=last){if(nums[i]<nums[j]){tmp[k++]=nums[i++];}else{tmp[k++]=nums[j++];}}while(i<=mid){tmp[k++]=nums[i++];}while(j<=last){tmp[k++]=nums[j++];}for(int t=start;t<=last;t++){nums[t]=tmp[t-start];}}void mergeSort(vector<int>& nums,int start,int last){if(start<last){int mid=(start+last)/2;mergeSort(nums,start,mid);mergeSort(nums,mid+1,last);mergeArray(nums,start,mid,last);}}void heapAdjust(vector <int> & arr, int parent,int N){int largest = parent;int child=2*parent+1;while(child<N)//N代表整个数组的元素个数,下标从0开始,child必须小于N{if(arr[child]>arr[largest]){largest=child;}if(child+1<N&&arr[child+1]>arr[largest]){largest=child+1;child++;//更新child的值}swap(arr[parent],arr[largest]);//交换parent=largest;// parent=child;在没有child大于parent的时候,largest还是parent,child是2*parent+1,所以不能这么写child=2*child+1;}// int left = 2*parent+1;// int right = 2*parent+2;// if(left < N && arr[left] > arr[largest])//     largest = left;// if(right < N && arr[right] > arr[largest])//     largest = right;// if(largest != parent){//     swap(arr[parent], arr[largest]);//     heapAdjust(arr,largest,N);// }}void heapSort(vector<int>& nums){for(int i = nums.size()/2; i >= 0; i--){//从最后一个非叶子节点开始调整heapAdjust(nums,i,nums.size());}for(auto it:nums){cout<<it<<endl;}for(int i = nums.size()-1; i >= 0; i--){swap(nums[0] , nums[i]);//下标0存放的是调整后最大值,交换后放到下标 i(当前未排序的最后位置)heapAdjust(nums,0,i);//i表示调整的元素个数,i从 size()-1  开始}}vector<int> sortArray(vector<int>& nums) {// quickSort(nums,0,nums.size()-1);// selectSort(nums);// insertSort(nums);// mergeSort(nums,0,nums.size()-1);heapSort(nums);return nums;}};

复杂度汇总 

 

这篇关于912. Sort an Array排序复习 快速排序,选择排序,插入排序,归并排序,堆排序的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

如何选择适合孤独症兄妹的学校?

在探索适合孤独症儿童教育的道路上,每一位家长都面临着前所未有的挑战与抉择。当这份责任落在拥有孤独症兄妹的家庭肩上时,选择一所能够同时满足两个孩子特殊需求的学校,更显得尤为关键。本文将探讨如何为这样的家庭做出明智的选择,并介绍星贝育园自闭症儿童寄宿制学校作为一个值得考虑的选项。 理解孤独症儿童的独特性 孤独症,这一复杂的神经发育障碍,影响着儿童的社交互动、沟通能力以及行为模式。对于拥有孤独症兄

电脑桌面文件删除了怎么找回来?别急,快速恢复攻略在此

在日常使用电脑的过程中,我们经常会遇到这样的情况:一不小心,桌面上的某个重要文件被删除了。这时,大多数人可能会感到惊慌失措,不知所措。 其实,不必过于担心,因为有很多方法可以帮助我们找回被删除的桌面文件。下面,就让我们一起来了解一下这些恢复桌面文件的方法吧。 一、使用撤销操作 如果我们刚刚删除了桌面上的文件,并且还没有进行其他操作,那么可以尝试使用撤销操作来恢复文件。在键盘上同时按下“C

【数据结构】——原来排序算法搞懂这些就行,轻松拿捏

前言:快速排序的实现最重要的是找基准值,下面让我们来了解如何实现找基准值 基准值的注释:在快排的过程中,每一次我们要取一个元素作为枢纽值,以这个数字来将序列划分为两部分。 在此我们采用三数取中法,也就是取左端、中间、右端三个数,然后进行排序,将中间数作为枢纽值。 快速排序实现主框架: //快速排序 void QuickSort(int* arr, int left, int rig

usaco 1.3 Mixing Milk (结构体排序 qsort) and hdu 2020(sort)

到了这题学会了结构体排序 于是回去修改了 1.2 milking cows 的算法~ 结构体排序核心: 1.结构体定义 struct Milk{int price;int milks;}milk[5000]; 2.自定义的比较函数,若返回值为正,qsort 函数判定a>b ;为负,a<b;为0,a==b; int milkcmp(const void *va,c

C#实战|大乐透选号器[6]:实现实时显示已选择的红蓝球数量

哈喽,你好啊,我是雷工。 关于大乐透选号器在前面已经记录了5篇笔记,这是第6篇; 接下来实现实时显示当前选中红球数量,蓝球数量; 以下为练习笔记。 01 效果演示 当选择和取消选择红球或蓝球时,在对应的位置显示实时已选择的红球、蓝球的数量; 02 标签名称 分别设置Label标签名称为:lblRedCount、lblBlueCount

透彻!驯服大型语言模型(LLMs)的五种方法,及具体方法选择思路

引言 随着时间的发展,大型语言模型不再停留在演示阶段而是逐步面向生产系统的应用,随着人们期望的不断增加,目标也发生了巨大的变化。在短短的几个月的时间里,人们对大模型的认识已经从对其zero-shot能力感到惊讶,转变为考虑改进模型质量、提高模型可用性。 「大语言模型(LLMs)其实就是利用高容量的模型架构(例如Transformer)对海量的、多种多样的数据分布进行建模得到,它包含了大量的先验

hdu 1285(拓扑排序)

题意: 给各个队间的胜负关系,让排名次,名词相同按从小到大排。 解析: 拓扑排序是应用于有向无回路图(Direct Acyclic Graph,简称DAG)上的一种排序方式,对一个有向无回路图进行拓扑排序后,所有的顶点形成一个序列,对所有边(u,v),满足u 在v 的前面。该序列说明了顶点表示的事件或状态发生的整体顺序。比较经典的是在工程活动上,某些工程完成后,另一些工程才能继续,此时

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个?

跨平台系列 cross-plateform 跨平台应用程序-01-概览 cross-plateform 跨平台应用程序-02-有哪些主流技术栈? cross-plateform 跨平台应用程序-03-如果只选择一个框架,应该选择哪一个? cross-plateform 跨平台应用程序-04-React Native 介绍 cross-plateform 跨平台应用程序-05-Flutte

hdu 4565 推倒公式+矩阵快速幂

题意 求下式的值: Sn=⌈ (a+b√)n⌉%m S_n = \lceil\ (a + \sqrt{b}) ^ n \rceil\% m 其中: 0<a,m<215 0< a, m < 2^{15} 0<b,n<231 0 < b, n < 2^{31} (a−1)2<b<a2 (a-1)^2< b < a^2 解析 令: An=(a+b√)n A_n = (a +