算法基础(1):排序和查找算法

1、排序算法

在这里插入图片描述

1.1、堆排序(大顶堆)-重点:

  • 参考文章:堆排序1、堆排序二

  • 前置知识:

    • 大顶堆:完全二叉树,且父节点大于左右儿子,左右子树又是大顶堆,依赖数组来实现(vector)
    • 第一个节点的父节点:(i-1)/2,第i个节点的左儿子:i*2+1,第i个节点的右儿子:i*2+2,这里i从0开始;
    • 最后有儿子的节点:数组元素有n个,则最后一个有儿子的节点(n-1-1)/2=n/2-1
  • 堆排序基本思想:分为建堆排序两步,而核心步骤是对堆的属性进行维护

    • 维护堆:维护第i个节点的堆属性, 将该节点和左右儿子节点进行对比,选择大的进行交换,然后向下遍历,直到全部都满足堆的属性
    • 建堆:对已有的数组,从最后一个有儿子的节点开始向上遍历建立大顶堆,每次都需要维护节点的堆属性
    • 排序:每次将第一个元素和最后一个元素进行交换,每次交换,需要维护的数组长度-1,维护的节点是第一个节点
  • 复杂度:

    • 时间复杂度:最坏、最好、平均时间复杂度均为O(nlogn)
    • 空间复杂度O(1)
    • 描述是个不稳定的内部排序算法
  • 代码实现:实列测试

    class Solution {
    public:void heapify(vector<int>& nums,int n,int i) //维护第i个节点的堆结构{int largest = i;int left = i*2+1;//最多遍历树的高度,时间复杂度O(log n)while(left<n) //当left是最后一个节点,也还需要判断一次{if(left<n&&nums[largest]<nums[left]) largest = left; if(left+1<n&&nums[largest]<nums[left+1]) largest = left+1; //if(largest==i) break; //当没有子节点的时候,或者不需要维护的时候跳出whileswap(nums[largest],nums[i]); //将大的值放到i的位置上i = largest; //向下循环子节点left = i*2+1; //子节点的左儿子}}void heapSort(vector<int>& nums,int n){//建堆时间复杂度O(nlog n),从第一个有子节点的节点开始维护for(int i =n/2-1;i>=0;i--)         {heapify(nums,n,i); }for(int i=n-1;i>=0;i--) //堆排序 时间复杂度O(nlogn){ //每次将最后一个节点和第一个节点互换swap(nums[i],nums[0]);heapify(nums,i,0); //进行枝剪维护第0个节点}}vector<int> sortArray(vector<int>& nums) {heapSort(nums,nums.size());return nums;}
    };
    

1.2、快速排序-重点

  • 快速排序基本思想:在区间中,每次选择一个基点,小于基点的放在基点左边,大于基点的放在右边,分别对两边进行快速排序
  • 复杂度:
    • 时间复杂度:最好、平均时间复杂度为O(nlogn),最坏时间复杂度O(n^2)-序列基本有序,递归O(n)
    • 空间复杂度: 递归深度 O(log n)
    • 描述是个不稳定的内部排序
  • 代码实现:参考视频
    • 二路快排,普通快排

      class Solution {
      public:int partition(vector<int>& nums,int l,int r){int pivot = rand()%(r-l+1)+l;swap(nums[pivot],nums[r]);int i=l;for(int j=l;j<=r-1;j++) //用j遍历数组,{if(nums[j]<nums[r]){swap(nums[j],nums[i]);  //指针i始终指向pivot右边的第一个元素i++; //i前面的都是小于pivot的元素,}}//遍历完了,i依旧指向大于pivot的元素的第一位// j指向r的位置,也就是pivot的位置,只需要将pivot的位置和i的位置进行交换即可swap(nums[r],nums[i]);return i;}void quikSort(vector<int>& nums,int left,int right){if(left>=right) return;int mid = partition(nums,left,right);quikSort(nums,left,mid-1);quikSort(nums,mid+1,right);}vector<int> sortArray(vector<int>& nums) {quikSort(nums,0,nums.size()-1);return nums;}
      };
      
    • 三路快排,用于重复元素多的情况

      class Solution {
      public:vector<int> partition(vector<int>& nums,int l,int r){int pivot = rand()%(r-l+1)+l;swap(nums[pivot],nums[r]);// 三路快排,p指向pivot元素相同的第一个元素// i指向大于pivot的元素的第一个位置int i=l;int p=l;for(int j=l;j<=r-1;j++){if(nums[j]<nums[r]){swap(nums[j],nums[i]);swap(nums[i],nums[p]);i++; p++;}else if(nums[j]==nums[r]){swap(nums[j],nums[i]);i++;}}swap(nums[r],nums[i]);return vector<int>{p,i};}void quikSort(vector<int>& nums,int left,int right){if(left>=right) return;vector<int> v = partition(nums,left,right);quikSort(nums,left,v[0]-1);quikSort(nums,v[1]+1,right);}vector<int> sortArray(vector<int>& nums) {quikSort(nums,0,nums.size()-1);return nums;}
      };
      

1.3、归并排序-重点

  • 归并排序基本思想:分治的思想,每将数组递归分成长度接近的两个部分,再进行排序合并回溯
  • 复杂度
    • 时间复杂度:平均、最好、最坏均为O(nlogn)
    • 空间复杂度:需要引入辅助空间O(n),如果是给链表排序则只需要O(1)
    • 描述:是个稳定的外部排序算法
  • 代码实现:
    • 数组归并
    class Solution {
    public:void merge(vector<int>&nums,vector<int>& arr,int left,int mid,int right){int l = left;//左边第一个未排序元素int r = mid+1;//右边第一个未排序元素int pos = left;//arr数组// 合并while(l<=mid&&r<=right){if(nums[l]<nums[r]) arr[pos++] = nums[l++];else arr[pos++] = nums[r++];}//合并剩余元素while(l<=mid) arr[pos++] = nums[l++];while(r<=right) arr[pos++] = nums[r++];//将临时数组进行拷贝while(left<=right){nums[left] = arr[left];left++;}}void mergeSort(vector<int>& nums,vector<int>& arr,int left,int right){ if(left>=right) return;int mid = (right+left)/2;mergeSort(nums,arr,left,mid);mergeSort(nums,arr,mid+1,right);merge(nums,arr,left,mid,right);}vector<int> sortArray(vector<int>& nums) {vector<int> arr(nums.size());mergeSort(nums,arr,0,nums.size()-1);return nums;}
    };
    
    • 链表归并:

1.4、冒泡排序

  • 冒泡排序基本思想:每次循环将最大元素交换到最右边,每次内部循环都需要交换

  • 和选择排序的区别:异曲同工,选择排序交换次数少,但是在数组有序的情况下,依旧需要完整的遍历完,时间复杂度稳定到O(n^2),冒泡排序,可以在数组有序的情况下提前结束

  • 复杂度:

    • 时间复杂度:平均时间复杂度O(n^2),最好时间复杂度O(n),平均时间复杂度O(n^2) - 空间复杂度:O(1)
    • 描述:是个稳定的内部排序
  • 代码实现:

    // 简单版本,和选择排序基本一致
    class Solution {
    public:void bubbleSort(vector<int>& nums,int n){for(int i=nums.size()-1;i>=0;i--){for(int j=0;j<i;++j){if(nums[j]>nums[j+1]) swap(nums[j],nums[j+1]);}}}vector<int> sortArray(vector<int>& nums) {bubbleSort(nums,nums.size());return nums;}
    };
    // 优化版本class Solution {public:void bubbleSort(vector<int>& nums,int n){bool flag = false;for(int i=nums.size()-1;i>=0;i--){flag = false;for(int j=0;j<i;++j) //一般过去是有序的,则时间复杂度只有O(n){if(nums[j]>nums[j+1]){swap(nums[j],nums[j+1]);flag = true;}}if(!flag) break;}}vector<int> sortArray(vector<int>& nums) {bubbleSort(nums,nums.size());return nums;}};
    

1.5、选择排序

  • 选择排序基本思想:每次选择一个最大的元素排到后面,每次内部循环只需要交换一次

  • 复杂度:

    • 时间复杂度:最好、最坏、平均时间复杂度为O(n^2)
    • 空间复杂度:没有辅助容器为O(1)
    • 描述:是个不稳定的内部排序
  • 代码实现:

    class Solution {
    public:void selectSort(vector<int>& nums,int n){int Max=-1;for(int i=nums.size()-1;i>=0;i--){Max = i;for(int j=0;j<i;++j){if(nums[j]>nums[Max]) Max=j;}swap(nums[i],nums[Max]);}}vector<int> sortArray(vector<int>& nums) {selectSort(nums,nums.size());return nums;}
    };
    

1.6、插入排序

  • 插入排序基本思想:每次将一个元素插入到前面维护好顺序的元素里面

  • 复杂度:

    • 时间复杂度:最坏、平均为O(n^2),最好为O(n)-基本有序的情况
    • 空间复杂度:O(1)
    • 描述:是个稳定的内部排序算法
  • 代码实现:

    class Solution {
    public:void InsertSort(vector<int>& nums,int n){for(int i=1;i<n;++i){// 每次将第i个元素插入到前i-1数组中int tmp = nums[i]; int j=i;while(j>0 && nums[j-1]>tmp){nums[j] = nums[j-1];--j;}nums[j] = tmp;}}vector<int> sortArray(vector<int>& nums) {InsertSort(nums,nums.size());return nums;}
    };
    

2、查找算法

2.1、二分查找

  • 基本思想:前提是数组有序,通过中间点折半的思想实现快速的查找

  • 红蓝边界思想:

    int left = -1,right = N; // 数组下标从0到N-1
    while left+1!=rightm = (left+right)/2;if IsBlue(m)left = m;else right = m;
    return left or right;  //返回值根据题目要求来定
    
  • 复杂度:

    • 时间复杂度:O(log n)
  • 代码实现:

    • 在有序数组中查找元素的下标:测试实列

      class Solution {
      public:/*红蓝边界求值,时间复杂度O(log n)1.没有这个元素的话,且right进行了移动2.没有这个元素的话,且right没有进行移动3.有这个元素,直接返回right*/int search(vector<int>& nums, int target) {int left = -1;int right = nums.size();while(left+1!=right){int mid = (left+right)/2;if(nums[mid]<target) left = mid;else right = mid;}//需要判断对应的节点不存在的可能if(right==nums.size()||nums[right]!=target) return -1; else return right;}
      };
      

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

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

相关文章

【Rust】Rust学习 第十六章无畏并发

安全且高效的处理并发编程是 Rust 的另一个主要目标。并发编程&#xff08;Concurrent programming&#xff09;&#xff0c;代表程序的不同部分相互独立的执行&#xff0c;而 并行编程&#xff08;parallel programming&#xff09;代表程序不同部分于同时执行&#xff0c;这两…

C# 反编译dll文件,将dll文件转为cs文件

工具名&#xff1a;reflector&#xff0c;可免费使用 工具下载地址使用方法 工具下载地址 下载地址&#xff1a; https://www.red-gate.com/products/reflector/ 使用方法 下载安装&#xff1b; 打开软件 打开dll文件 侧边栏找打刚打开的dll文件&#xff0c;直接就能导…

Redisson 分布式锁

Redis是基础客户端库&#xff0c;可用于执行基本操作。 Redisson是基于Redis的Java客户端&#xff0c;提供高级功能如分布式锁、分布式集合和分布式对象。 Redisson提供更友好的API&#xff0c;支持异步和响应式编程&#xff0c;提供内置线程安全和失败重试机制。 实现步骤…

密码学学习笔记(十八):Diffie–Hellman (DH) 密钥交换

DH算法是第一个密钥交换算法&#xff0c;也是第一个得到形式化描述的公钥密码算法。 群论 DH密钥交换算法基于数学中的群论&#xff0c;群论也是当今大多数公钥密码的基础。 要使集合及其运算成为一个群&#xff0c;需要满足以下性质&#xff1a; 封闭性&#xff1a;群中两…

使用three.js与WebGL相比有什么优势?

推荐&#xff1a;使用 NSDT场景编辑器 助你快速搭建可二次编辑的3D应用场景 特点 WebGL和Three.js是两个与网页3D图形渲染相关的技术。以下是它们的一些特点&#xff1a; WebGL: 基于OpenGL ES标准&#xff0c;为网页提供了一种基于GPU加速的图形渲染API。具有高性能的图像处…

【从零学习python 】75. TCP协议:可靠的面向连接的传输层通信协议

文章目录 TCP协议TCP通信的三个步骤TCP特点TCP与UDP的区别TCP通信模型进阶案例 TCP协议 TCP协议&#xff0c;传输控制协议&#xff08;英语&#xff1a;Transmission Control Protocol&#xff0c;缩写为 TCP&#xff09;是一种面向连接的、可靠的、基于字节流的传输层通信协议…

在思科(Cisco)设备上配置 DHCP 服务器

DHCP广泛用于LAN环境中&#xff0c;从集中式服务器动态分配主机IP地址&#xff0c;从而显着减少IP地址管理的开销。DHCP 还有助于节省有限的 IP 地址空间&#xff0c;因为不再需要将 IP 地址永久分配给主机&#xff0c;只有连接到网络的主机才会使用 IP 地址。DHCP 服务器将路由…

网络聊天室

一、项目要求 利用UDP协议&#xff0c;实现一套聊天室软件。服务器端记录客户端的地址&#xff0c;客户端发送消息后&#xff0c;服务器群发给各个客户端软件。 问题思考 客户端会不会知道其它客户端地址&#xff1f; UDP客户端不会直接互连&#xff0c;所以不会获知其它客…

详解使用SSH远程连接Ubuntu服务器系统

演示环境&#xff1a; 1.Windows10系统 2.VMware Workstation Pro虚拟机 2.Ubuntu16.04.6&#xff08;以上版本通用&#xff09; 回归正题 一、在Ubuntu端&#xff1a; 1.首先需要安装SSH服务器&#xff0c;在ubuntu终端输入以下指令 sudo apt-get install ssh2.输入你的ubu…

判断三角形

int main() {int a 0;int b 0;int c 0;scanf("%d%d%d", &a, &b, &c);if ((ab>c)&&(ac>b)&&(bc>a)){if (a b && b c){printf("等边三角形\n");}else if ((a b && b ! c) || (a c && c…

网约车接单神器:智能化技术与出行服务的完美结合

随着移动互联网的迅猛发展&#xff0c;网约车行业成为现代出行方式的主流之一。为了提高用户体验和服务效率&#xff0c;网约车接单神器应运而生。本文将探讨网约车接单神器的专业性、思考深度和逻辑性&#xff0c;以及其与智能化技术和出行服务的完美结合。 一、引言&…

leetcode 309. 买卖股票的最佳时机含冷冻期

2023.8.22 本题是买卖股票系列 冷冻期。 由于引入了冷冻期&#xff0c;并且这个冷冻期是在卖出股票才会出现&#xff0c;因此我dp数组设置了四种状态&#xff1a; 状态一&#xff1a;持有股票。状态二&#xff1a;不持有股票&#xff1a; 之前就卖了&#xff0c;所以今天不处…

论AI与大数据之间的关系

前言 在21世纪&#xff0c;"AI"和"大数据"已经成为科技领域的热门词汇。它们不仅是创新的代名词&#xff0c;更是现代技术发展的双翼。然而&#xff0c;很多人对于AI与大数据之间的关系仍然停留在表面的理解。本文旨在深入探讨这两者之间的深厚关系&#…

设置Windows主机的浏览器为wls2的默认浏览器

1. 准备工作 wsl是可以使用Windows主机上安装的exe程序&#xff0c;出于安全考虑&#xff0c;默认情况下改功能是无法使用。要使用的话&#xff0c;终端需要以管理员权限启动。 我这里以Windows Terminal为例&#xff0c;介绍如何默认使用管理员权限打开终端&#xff0c;具体…

[LeetCode111双周赛LeetCode359周赛] DP双指针

参考灵神和闫总的讲解和代码&#xff1a; https://www.bilibili.com/video/BV1rP411s7Z5 https://space.bilibili.com/206214 7006. 销售利润最大化 https://leetcode.cn/problems/maximize-the-profit-as-the-salesman/ Solution 动态规划 哈希表 首先按照 end 的顺序分…

kafka-- kafka集群 架构模型职责分派讲解

一、 kafka集群 架构模型职责分派讲解 生产者将消息发送到相应的Topic&#xff0c;而消费者通过从Topic拉取消息来消费 Kafka奇数个节点消费者consumer会将消息拉去过来生产者producer会将消息发送出去数据管理 放在zookeeper

jmeter HTTP请求默认值

首先&#xff0c;打开JMeter并创建一个新的测试计划。 右键单击测试计划&#xff0c;选择"添加" > “配置元件” > “HTTP请求默认值”。 在HTTP请求默认值中&#xff0c;您可以设置全局的HTTP请求属性&#xff0c;例如&#xff1a; 服务器地址&#xff1a…

数据结构——队列(C语言)

需求&#xff1a;无 本篇文章将解决一下几个问题&#xff1a; 队列是什么&#xff1f;如何实现一个队列&#xff1f;什么场景下会用队列&#xff1f; 队列的概念&#xff1a; 队列&#xff1a;一种只允许一端进行插入数据操作&#xff0c;在另一端进行删除操作的特殊线性表。…

Redis数据结构之List

Redis 中列表&#xff08;List&#xff09;类型是用来存储多个有序的字符串&#xff0c;列表中的每个字符串成为元素 Eelement&#xff09;&#xff0c;一个列表最多可以存储 2^32-1 个元素。 在 Redis 中&#xff0c;可以对列表两端插入&#xff08;push&#xff09;和弹出&am…

jenkins 是什么?

一、jenkins 是什么&#xff1f; Jenkins是一个开源的、提供友好操作界面的持续集成(CI)工具&#xff0c;起源于Hudson&#xff0c;主要用于持续、自动的构建/测试软件项目、监控外部任务的运行。Jenkins用Java语言编写&#xff0c;可在Tomcat等流行的servlet容器中运行&#…