面试常用排序查找算法

文章目录

      • 1 二分查找
      • 2 冒泡排序
      • 3 堆排序
      • 4 插入排序
      • 5 快速排序
      • 6 选择排序
      • 7 希尔排序

1 二分查找

  1. 定义两个变量leftright,分别表示数组的左边界和右边界,初始值分别为0len - 1,其中len是数组的长度。
  2. 计算数组的中间位置mid,公式为(left + right) / 2,并判断数组中该位置的元素num[mid]是否等于目标值target
  3. 如果相等,说明找到了目标值,返回mid作为结果。
  4. 如果不相等,比较num[mid]target的大小,如果num[mid] < target,说明目标值在数组的右半部分,因此将左边界更新为mid + 1;如果num[mid] > target,说明目标值在数组的左半部分,因此将右边界更新为mid - 1
  5. 重复步骤2到4,直到左边界大于右边界,这时说明数组中不存在目标值,返回-1作为结果。

  二分查找算法的优点是查找速度快,时间复杂度为 O ( l o g n ) O(logn) O(logn),其中n是数组的长度。缺点是要求数组必须是有序的,并且对于动态变化的数组不适用。

int BinarySearch(int num[],int target,int len)
{int left = 0, right = len - 1;while(left <= right){int mid = (left + right) / 2;if(num[mid]==target){return mid;}else if(num[mid] < target){left = mid + 1;}else{right = mid - 1;}}return -1;
}

2 冒泡排序

  1. 定义一个变量i,表示数组中未排序的部分的最后一个元素的位置,初始值为length - 1,其中length是数组的长度。
  2. 从数组的第一个元素开始,依次比较相邻的两个元素,如果前一个元素num[j]大于后一个元素num[j+1],则交换它们的位置,这样可以将较大的元素向后移动。
  3. 重复步骤2,直到遍历到数组中未排序部分的最后一个元素,这时可以确定该元素是数组中最大的元素,并将其排在正确的位置。
  4. 将变量i减一,表示数组中未排序部分的长度减少了一个元素,然后回到步骤2,继续进行比较和交换。
  5. 重复步骤2到4,直到变量i小于等于1,这时说明数组中所有的元素都已经排好序,算法结束。

  冒泡排序算法的优点是简单易懂,不需要额外的空间。缺点是效率低,时间复杂度为 O ( n 2 ) O(n^2) O(n2),其中n是数组的长度。

void BubbleSort(int num[],int length)
{for(int i=length-1;i>1;i--){for(int j=0;j<i;j++){if(num[j] > num[j+1]){int tmp = num[j+1];num[j+1] = num[j];num[j] = tmp;}}}
}

3 堆排序

  1. 定义一个函数MaxHeap,它的作用是将一个数组中的一部分元素调整为一个大根堆,即满足父节点的值大于等于子节点的值的二叉树。函数的参数有三个,分别是num表示数组,start表示调整的起始位置,end表示调整的结束位置。
  2. 在函数MaxHeap中,定义两个变量dadson,分别表示当前要调整的父节点和子节点的位置,初始值分别为startstart * 2 + 1(因为数组下标从0开始,所以左子节点是父节点乘以2再加1)。
  3. 判断子节点是否在调整范围内,如果是,则继续执行以下步骤;如果不是,则说明已经调整完毕,返回。
  4. 如果存在右子节点,并且右子节点的值大于左子节点的值,则将子节点更新为右子节点(即选择较大的子节点)。
  5. 比较父节点和子节点的值,如果父节点的值大于等于子节点的值,则说明已经满足大根堆的性质,返回;如果不是,则交换父节点和子节点的值,并将父节点更新为原来的子节点,子节点更新为原来父节点的左子节点(即向下一层继续调整)。
  6. 重复步骤3到5,直到调整完毕或者返回。
  7. 定义一个函数HeapSort,它的作用是对一个数组进行堆排序。函数的参数有两个,分别是num表示数组,len表示数组的长度。
  8. 从数组中间位置开始,依次对每个元素执行函数MaxHeap,这样可以将整个数组调整为一个大根堆(即第一个元素是最大的元素)。
  9. 从数组最后一个元素开始,依次执行以下步骤:
    • 交换第一个元素和当前元素的值,这样可以将最大的元素放在正确的位置。
    • 对除了当前元素之外的其他元素执行函数MaxHeap,这样可以将剩余部分重新调整为一个大根堆(即第一个元素是剩余部分最大的元素)。
  10. 重复步骤9,直到只剩下第一个元素,这时说明数组中所有的元素都已经排好序,算法结束。

  堆排序算法的优点是效率高,时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),其中n是数组的长度。缺点是需要额外的空间来存储堆结构,并且对于稳定性要求高的场合不适用。

void MaxHeap(int num[],int start,int end)
{int dad = start;int son = dad * 2 + 1;while(son <=end){if((son+1<=end) && (num[son]<num[son+1])){son++;}if(num[son]<num[dad]){return;}else{int tmp = num[dad];num[dad] = num[son];num[son] = tmp;dad = son;son = dad * 2 + 1;}}
}void HeapSort(int num[],int len)
{for(int i=len/2-1;i>=0;i--){MaxHeap(num,i,len-1);}for(int i=len-1;i>0;i--){int tmp = num[0];num[0] = num[i];num[i] = tmp;MaxHeap(num,0,i-1);}
}

4 插入排序

  1. 定义一个变量i,表示当前要插入的元素的位置,初始值为1,表示从数组的第二个元素开始。
  2. 将当前要插入的元素num[i]保存在一个临时变量tmp中,以免被覆盖。
  3. 定义一个变量j,表示已经排好序的部分的最后一个元素的位置,初始值为i - 1
  4. 比较已经排好序的部分的最后一个元素num[j]和要插入的元素tmp的大小,如果前者大于后者,则将前者向后移动一位,即将num[j]赋值给num[j+1],并将j减一;如果不是,则说明找到了要插入的位置,跳出循环。
  5. 将要插入的元素tmp赋值给找到的位置,即将tmp赋值给num[j+1]
  6. 将变量i加一,表示要插入下一个元素,并回到步骤2,继续进行比较和移动。
  7. 重复步骤2到6,直到变量i等于数组的长度,这时说明数组中所有的元素都已经排好序,算法结束。

  插入排序算法的优点是简单易懂,对于部分有序或者数据量较小的数组效率较高。缺点是效率低,时间复杂度为 O ( n 2 ) O(n^2) O(n2),其中n是数组的长度。

void InsertSort(int num[],int length)
{for(int i=1;i<length;i++){int tmp = num[i];int j = i - 1;while((j>=0) && (num[j]>tmp)){num[j+1] = num[j];j--;}num[j+1] = tmp;}
}

5 快速排序

  1. 定义一个函数QuickSort,它的作用是对一个数组的一部分进行快速排序。函数的参数有三个,分别是num表示数组,start表示排序的起始位置,end表示排序的结束位置。
  2. 判断是否需要排序,如果起始位置大于等于结束位置,则说明已经排好序,返回;如果不是,则继续执行以下步骤。
  3. 定义两个变量ij,分别表示当前要划分的部分的左边界和右边界,初始值分别为startend
  4. 选择数组中第一个元素num[i]作为基准值,并将其保存在一个临时变量basenum中,以免被覆盖。
  5. 从右边界开始,向左寻找一个小于基准值的元素,如果找到,则将其赋值给左边界位置;如果没有找到,则将右边界减一,继续寻找。
  6. 从左边界开始,向右寻找一个大于基准值的元素,如果找到,则将其赋值给右边界位置;如果没有找到,则将左边界加一,继续寻找。
  7. 重复步骤5和6,直到左边界和右边界相遇或者交叉,这时说明已经完成了一次划分,并将基准值赋值给相遇或者交叉的位置。
  8. 对基准值左边的部分递归地执行函数QuickSort,对基准值右边的部分递归地执行函数QuickSort
  9. 重复步骤2到8,直到所有的部分都排好序,算法结束。

  快速排序算法的优点是效率高,时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn),其中n是数组的长度。缺点是不稳定,并且对于极端情况(如数组已经有序或者逆序)效率低。

void QuickSort(int num[],int start,int end)
{if(start >= end) return;int i = start;int j = end;int basenum = num[i];while(i<j){//从右往左找小值while((i<j) && (num[j]>=basenum)){j--;}if(i<j){num[i] = num[j];i++;}//从左往右找大值while((i<j) && (num[i]<basenum)){i++;}if(i<j){num[j] = num[i];j--;}num[i] = basenum;}QuickSort(num,start,i-1);QuickSort(num,i+1,end);
}

6 选择排序

  1. 定义一个变量i,表示当前要选择的位置,初始值为0,表示从数组的第一个元素开始。
  2. 定义一个变量min,表示当前最小元素的位置,初始值为i
  3. 从当前位置开始,向后遍历数组中的每个元素,如果发现有比当前最小元素更小的元素,则将其位置赋值给min,这样可以找到当前范围内最小的元素。
  4. 交换当前位置和最小元素的值,即将num[min]赋值给num[i],将num[i]赋值给num[min],这样可以将最小的元素放在正确的位置。
  5. 将变量i加一,表示要选择下一个位置,并回到步骤2,继续进行选择和交换。
  6. 重复步骤2到5,直到变量i等于数组的长度减一,这时说明数组中所有的元素都已经排好序,算法结束。

  选择排序算法的优点是简单易懂,不需要额外的空间。缺点是效率低,时间复杂度为 O ( n 2 ) O(n^2) O(n2),其中n是数组的长度。

void SelectSort(int num[],int length)
{for(int i=0;i<length-1;i++){int min = i;for(int j=i;j<length;j++){if(num[j]<num[min]){min = j;}}int tmp = num[min];num[min] = num[i];num[i] = tmp;}
}

7 希尔排序

  1. 定义一个变量gap,表示当前要排序的元素的间隔,初始值为数组的长度length
  2. 计算新的间隔,公式为gap = gap / 3 + 1,这样可以逐渐减小间隔,直到为1。
  3. 对每个间隔进行以下步骤:
    • 定义一个变量i,表示当前要排序的间隔的起始位置,初始值为0
    • 从当前位置开始,向后遍历数组中的每个间隔内的元素,如果发现有比前一个间隔内的元素更小的元素,则将其保存在一个临时变量tmp中,并执行以下步骤:
      • 定义一个变量k,表示已经排好序的部分的最后一个间隔内的元素的位置,初始值为当前位置减去间隔,即k = j - gap
      • 比较已经排好序的部分的最后一个间隔内的元素num[k]和要插入的元素tmp的大小,如果前者大于后者,则将前者向后移动一个间隔,即将num[k]赋值给num[k+gap],并将k减去间隔,继续比较;如果不是,则说明找到了要插入的位置,跳出循环。
      • 将要插入的元素tmp赋值给找到的位置,即将tmp赋值给num[k+gap]
    • 将变量i加一,表示要排序下一个间隔,并回到步骤3.2,继续进行遍历和插入。
  4. 重复步骤2和3,直到变量gap等于1,这时说明数组中所有的元素都已经排好序,算法结束。

  希尔排序算法的优点是效率高于简单插入排序,时间复杂度为 O ( n 1.3 ) O(n^{1.3}) O(n1.3),其中n是数组的长度。缺点是不稳定,并且对于不同的间隔选择效率有影响。

void ShellSort(int num[],int length)
{int gap = length;do{gap = gap / 3 + 1;for(int i=0;i<gap;i++){for(int j=gap+i;j<length;j+=gap){if(num[j] < num[j-gap]){int tmp = num[j];int k;for(k=j-gap;(k>=0) && (num[k]>tmp);k-=gap){num[k+gap] = num[k];}num[k+gap] = tmp;}}}} while(gap>1);
}

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

什么是FOSS

FOSS 是指 自由和开放源码软件(Free and Open Source Software)。这并不意味着软件是免费的。它意味着软件的源代码是开放的&#xff0c;任何人都可以自由使用、研究和修改代码。这个原则允许人们像一个社区一样为软件的开发和改进做出贡献。

CentOS密码重置

背景&#xff1a; 我有一个CentOS虚拟机&#xff0c;但是密码忘记了&#xff0c;偶尔记起可以重置密码&#xff0c;于是今天尝试记录一下&#xff0c;又因为我最近记性比较差&#xff0c;所以必须要记录一下。 过程&#xff1a; 1、在引导菜单界面&#xff08;grub&#xff…

如何实现电脑语音输入功能?

现在的手机都具备语音输入功能&#xff0c;并且识别率非常高&#xff0c;语音输入是目前最快速的文字输入方式&#xff0c;但是电脑上却无语音输入的功能&#xff0c;那么如何实现在电脑端也可进行语音输入的梦想呢&#xff1f;现在介绍一款小工具“书剑电脑语音输入法”&#…

java并发编程 守护线程 用户线程 main

经常使用线程&#xff0c;没有对守护线程和用户线程的区别做彻底了解 下面写4个例子来验证一下 源码如下 /* Whether or not the thread is a daemon thread. */ private boolean daemon false;/*** Marks this thread as either a {linkplain #isDaemon daemon} thread*…

Python|OpenCV-如何给目标图像添加边框(7)

前言 本文是该专栏的第7篇,后面将持续分享OpenCV计算机视觉的干货知识,记得关注。 在使用opencv处理图像的时候,会不可避免的对图像的一些具体区域进行一些操作。比如说,想要给目标图像创建一个围绕图像的边框。简单的来说,就是在图片的周围再填充一个粗线框。具体效果,…

OpenCV实现视频的读取、显示、保存

目录 1&#xff0c;从文件中读取视频并播放 1.2代码实现 1.3效果展示 2&#xff0c;保存视频 2.1 代码实现 2.2 结果展示 1&#xff0c;从文件中读取视频并播放 在OpenCV中我们需要获取一个视频&#xff0c;需要创建一个VideoCapture对象,指定你要读取的视频文件&am…

uni-app 实现凸起的 tabbar 底部导航栏

效果图 在 pages.json 中设置隐藏自带的 tabbar 导航栏 "custom": true, // 开启自定义tabBar(不填每次原来的tabbar在重新加载时都回闪现) 新建一个 custom-tabbar.vue 自定义组件页面 custom-tabbar.vue <!-- 自定义底部导航栏 --> <template><v…

【图像处理】【应用程序设计】加载,编辑和保存图像数据、图像分割、色度键控研究(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

【Java 进阶篇】JDBC(Java Database Connectivity)详解

JDBC&#xff08;Java Database Connectivity&#xff09;是 Java 中用于连接和操作数据库的标准 API。它允许 Java 应用程序与不同类型的数据库进行交互&#xff0c;执行查询、插入、更新和删除等操作。本文将详细介绍 JDBC 的各个类及其用法&#xff0c;以帮助您更好地理解和…

DDD项目落地之充血模型实践

一、背景 充血模型是DDD分层架构中实体设计的一种方案&#xff0c;可以使关注点聚焦于业务实现&#xff0c;可有效提升开发效率、提升可维护性&#xff1b; 二、DDD项目落地整体调用关系 调用关系图中的Entity为实体&#xff0c;从进入领域服务&#xff08;Domin&#xff09;…

在移动固态硬盘上安装Ubuntu系统和ROS2

目录 原视频准备烧录 原视频 b站鱼香ros 准备 1.在某宝上买一个usb移动固态硬盘或固态U盘&#xff0c;至少64G 2.下载鱼香ros烧录工具 下载第二个就行了&#xff0c;不然某网盘的速度下载全部要一天 下载后&#xff0c;选择FishROS2OS制作工具压缩包&#xff0c;进行解压…

WPS Office for Linux即将面临开源

WPS Office 是一款免费&#xff08;但不开源&#xff09;的办公套件&#xff0c;目前已经在 Windows、macOS、Android、iOS 和 Linux 设备上线&#xff0c;由于在界面和功能上模仿了微软 Office 的部分特性&#xff0c;对于那些轻量办公的用户来说已经能够完全驾驭大部分需求。…

vue3 element-ui-plus Carousel 跑马灯 的使用 及 踩坑记录

vue3 element-ui-plus Carousel 跑马灯 的踩坑记录 Carousel 跑马灯首页跑马灯demo Carousel 跑马灯 首先&#xff0c;打开其官网-跑马灯案例 跑马灯代码&#xff1a; <el-carousel :interval"5000" arrow"always"><el-carousel-item v-for"…

以32bit加法器为核心的加法、减法、乘法和除法计算器(ALU)

1 任务概述 实现一个以加法器为核心的计算器。 加法&#xff1a;能够实现32bit加法 减法&#xff1a;能够实现32bit减法 乘法&#xff1a;能够实现两个32bit数字的乘法&#xff0c;乘积为64bit 除法&#xff1a;能够实现两个32bit无符号数的除法&#xff0c;商为32bit&#xf…

【算法|贪心算法系列No.3】leetcode334. 递增的三元子序列

个人主页&#xff1a;兜里有颗棉花糖 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 兜里有颗棉花糖 原创 收录于专栏【手撕算法系列专栏】【LeetCode】 &#x1f354;本专栏旨在提高自己算法能力的同时&#xff0c;记录一下自己的学习过程&#xff0c;希望…

【MySQL入门到精通-黑马程序员】MySQL基础篇-DML

文章目录 前言一、DML-介绍二、DML-添加数据三、DML-修改数据四、DML-删除数据总结 前言 本专栏文章为观看黑马程序员《MySQL入门到精通》所做笔记&#xff0c;课程地址在这。如有侵权&#xff0c;立即删除。 一、DML-介绍 DML&#xff08;Data Manipulation Language&#xf…

湖南特色农产品销售系统APP /基于android的农产品销售系统/基于android的购物系统

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的APP应运而生&#xff0c;各行各业相继进入信息管理时代&#x…

25-多线程

多线程 线程(Thread)是一个程序内部的一条执行流程。 程序中如果有一条执行流程&#xff0c;那这个程序就是单线程的程序 多线程是指从软硬件上实现的多条执行流程的技术&#xff08;多条线程由CPU负责调度执行&#xff09;。 再例如&#xff1a;消息通信、淘宝、京东系统都离…

【Excel】快速提取某个符号前面的数据内容

【问题描述】 在使用excel整理数据过程中&#xff0c;经常与需要调整数据后&#xff0c;进行使用。 例如凭证导出后&#xff0c;科目列是包含科目编码和科目名称的。 但由于要将数据复制到其他的导入模板上使用&#xff0c;对应的模板只需要科目编码&#xff0c;不需要科目名称…

基于Java的校园失物招领平台设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…