经典 算法

算法

算法(Algorithm)是指解题方案的准确而完整的描述,是一系列解决问题的清晰指令。简单来说,算法 就是解决一个问题的具体方法和步骤。在计算机科学中,算法是程序设计的核心,它决定了程序如何执 行特定的任务。

算法的性能评价通常包括时间复杂度和空间复杂度两个方面。时间复杂度衡量了算法执行所需的时间资 源,而空间复杂度则衡量了算法执行所需的存储资源。

1.时间复杂度

它衡量了一个算法执行所需时间的相 对量度。

时间复杂度描述了算法运行时间与输入规模之间的增长关系。

间复杂度并不是算法执行所需的实际时间,因为实际时间会受到很多因素的影响,如处理器速度、编 译器优化、系统负载等。因此,时间复杂度是算法执行时间随输入规模增长而增长的“趋势”或“速率”的度 量。

  • 计算方式:

    • 时间(空间)复杂度计算公式:T(n)=O(f(n));

    • n :数据规模大小

    • T(n) :代码的执行时间

    • f(n) :每一行代码的执行的次数的总和(平常只关心量级最大的代码次数,忽略低阶、常数、系数)

  • 常见的时间复杂度有:

    • 常数时间复杂度 O(1):算法的执行时间不随输入规模的增长而增长,即无论输入数据有多大,算法的执

      行时间都是固定的。(数组访问)

    • 线性时间复杂度 O(n):算法的执行时间与输入规模呈线性关系,即算法的执行时间随着输入数据量的增

      加而线性增长。(单层循环)

    • 对数时间复杂度 O(log n):算法的执行时间与输入规模的对数成正比。(二分查找)

    • 线性对数时间复杂度 O(n log n):算法的执行时间随输入规模的增长而线性对数增长。(快速排序、归

      并排序)。

    • 平方时间复杂度 O(n^2):算法的执行时间与输入规模的平方成正比。(双重循环)。

2.空间复杂度

空间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度。具体来
说,它表示算法在计算机内存中执行时所需额外空间的度量,记作S(n),其中n是问题的规模(即输入数
据的大小)。这个空间包括算法在执行时所使用的所有额外存储空间,如变量(包括静态变量和动态变量)、递归调用栈、以及输入输出数据所占据的存储空间等。

计算方式类似于时间复杂度.

1 排序

排序算法是计算机程序设计中的一种重要操作,旨在将一组数据元素(或记录)按照某种关键字的大小 顺序,递增或递减地排列起来。排序算法在数据处理、数据库管理、搜索引擎优化等多个领域都有广泛 应用

注意:下文中的排序默认是升序!

1.1冒泡排序

通过重复遍历待排序的序列,从数组一端开始不断比较相邻元素的大小,并在必要时交换它们的位置,
直到没有元素需要交换为止。

在这里插入图片描述

示例 时间复杂度O(n^2)

#include <iostream>
using namespace std;//冒泡排序 时间复杂度O(n^2)
void bubble_sort(int *arr, int size)
{//每进行一轮排序,最大的元素都会被安排再最右边 size - 1是因为比较左右两个元素,最后一个元
// 素不用比较int tmp = 0;for(int i = 0; i < size - 1; i++){// / 对最大元素左边的所有数据重新排序,再找到其中最大的for(int j = 0; j < size - 1 - i;  j++){if(arr[j] > arr[j+1]){// 交换 arr[j] 和 arr[j+1]tmp = arr[j+1];arr[j+1] =  arr[j];arr[j] = tmp;}   }}
}int main()
{int arr[5] = {5, 2, 1, 3, 4 };bubble_sort(arr, 5);for(int i = 0; i < 5; i++){cout << arr[i] << " ";}cout << endl;return 0;
}

1.2 选择排序

首先在序列中找到最小元素,放到序列的起始位置作为已排序序列;
然后,再从剩余未排序元素中继续寻找最小元素,放到已排序序列的末尾;
重复上述步骤,直到所有元素均排序完成。

在这里插入图片描述

示例 时间复杂度O(n^2)

// 选择排序
void select_sort(int *arr, int size)
{int temp = 0;// 记录最小索引for(int i = 0; i < size - 1; i++){//假设当前索引就是iint MinNum = i;for(int j = MinNum + 1; j < size; j++){if(arr[j] < arr[MinNum]){MinNum = j;}}if(MinNum != i){temp = arr[MinNum];arr[MinNum] = arr[i];arr[i] = temp;}}
}
int main()
{int arr1[5] = { 2, 0, 1,3, 4 };select_sort(arr1, 5);for(int i = 0; i < 5; i++){cout << arr[i] << " ";}cout << endl;return 0;
}

1.3 插入排序

插入排序的基本思想是将数组分为已排序和未排序两部分,初始时,已排序部分只包含第一个元素,未
排序部分包含其余元素。

然后,依次将未排序部分的元素插入到已排序部分的适当位置,直到未排序部
分为空。

在这里插入图片描述

示例 时间复杂度O(n^2)

// 插入排序
void insertionSort(int *arr, int size)
{//默认第一个元素已经是有序的了for(int i = 1; i < size ;i++){// 有序位置int key =  arr[i];// 从后往前// j = i - 1 是用来从后往前比较的,这里的“后”是相对于当前要插入的元素 arr[i] 的位置而言的int j =  i - 1;while (j > 0 &&  arr[j] > key){arr[j + 1] = arr[j];j--; }arr[j + 1] = key;}
}
int main()
{ int arr2[5] = { 2, 6, 5, 3, 4 };insertionSort(arr2, 5);for(int i = 0; i < 5; i++){cout << arr2[i] << " ";}cout << endl;return 0;
}

***1.4 快速排序 (面试会问)

首先从序列中任意选择一个元素,把该元素作为基准(一般是第一个或者最后一个元素)。

然后将小于等于基准的所有元素都移到基准的左 侧,把大于枢轴的元素都移到枢轴的右侧,。基准元素不属于任一 子序列,并且基准元素当前所在位置就是该元素在整个排序完成后的最终位置。

这样一个划分左右子序列的过程就叫做快速排序的一趟排序,或称为一次划分。递归此划分过程,直到 整个序列有序。

算法图解

首先给出一个无序序列[3, 5, 4, 1, 2],选取一个元素为基准元素,一般选择序列第一个元素(或最后一个 元素),以3作为基准,然后设置两个指针,一个left指针指向左侧第一个位置,一个right指针指向右 侧最后一个位置。

在这里插入图片描述

首先取出基准元素3,此时left指向的位置留出一个空位。为了好理解说是空位,其实是指向基准值

我们规定,指向**空(基准值)**的指针不移动。

此时应该操作right指针

  • 如果right指针指向的元素大于基准元素3,那么right指针左移;

  • 如果right指针指向的元素小于基准元素3,那么将right指针指向的元素放到left指针指向的空

    位处(保证左边的元素都比基准小,右边元素都基准大),同时left指针右移。

显然,当前right指向的2小于3,所以把2放到left指向的位置,此时right指向为空。

在这里插入图片描述

right指针指向空,操作left指针, 对left指针: 如果left指针指向元素小于基准元素3,那么left指针右移

对left指针:

  • 如果left指针指向元素小于基准元素3,那么left指针右移;
  • 如果left指针指向元素大于基准元素3,那么把left指针指向的元素放到right指向的空位处。

在这里插入图片描述

此时,5大于3,元素放到right,同时right指针左移 )

在这里插入图片描述

left指针指向空,操作right指针,此时,1小于3,元素放到left,同时left指针右移

!
%BA%8F%5C5.png&pos_id=img-QZQXfVx8-1747289875468)

right指针指向空,操作left指针,此时,4大于3,元素放到right,同时right指针左移

在这里插入图片描述

left指针和right指针指向同一个位置,此时将基准元素插入。

在这里插入图片描述

最后得到的序列,3左侧全部是小于3的元素,3右侧全部是大于3的元素

然后重复上述步骤,对基准左右两边同时进行快速排序

`示例

时间复杂度O(n logn)`

#include <iostream>
using namespace std;//冒泡排序 时间复杂度O(n^2)
void bubble_sort(int *arr, int size)
{//每进行一轮排序,最大的元素都会被安排再最右边 size - 1是因为比较左右两个元素,最后一个元
// 素不用比较int tmp = 0;for(int i = 0; i < size - 1; i++){// / 对最大元素左边的所有数据重新排序,再找到其中最大的for(int j = 0; j < size - 1 - i;  j++){if(arr[j] > arr[j+1]){// 交换 arr[j] 和 arr[j+1]tmp = arr[j+1];arr[j+1] =  arr[j];arr[j] = tmp;}   }}
}// 选择排序
void select_sort(int *arr, int size)
{int temp = 0;// 记录最小索引for(int i = 0; i < size - 1; i++){//假设当前索引就是iint MinNum = i;for(int j = MinNum + 1; j < size; j++){if(arr[j] < arr[MinNum]){MinNum = j;}}if(MinNum != i){temp = arr[MinNum];arr[MinNum] = arr[i];arr[i] = temp;}}
}// 插入排序
void insertionSort(int *arr, int size)
{//默认第一个元素已经是有序的了for(int i = 1; i < size ;i++){// 有序位置int key =  arr[i];// 从后往前// j = i - 1 是用来从后往前比较的,这里的“后”是相对于当前要插入的元素 arr[i] 的位置而言的int j =  i - 1;while (j > 0 &&  arr[j] > key){arr[j + 1] = arr[j];j--; }arr[j + 1] = key;}
}// 快速排序
void quick_sort(int *p_num, int size)
{int base =  *p_num; //基准,选在开头int *left = p_num;      //左指针int *right = p_num + size - 1;      //右指针int temp = 0;// int *temp  == nullptr error// temp是一个指针,它用于存储内存地址。在你的代码中,你试图用 *temp 来存储交换的值,// 但 temp 没有指向一个有效的内存地址,所以这种操作是非法的。这就像你有一个指向空房间的门(指针),但你却试图把东西放进这个不存在的房间里if(size <= 1){return; //递归出口}while( left < right)//指针比较{if( *left > *right)//指针指向的值比较{temp = *left;*left  = *right;*right =  temp;}// 等于基准值的指针不移动// 左指针等于基准右指针前移if( *left == base){right--;}// 右指针等于基准左指针后移else{left++;}}// 递归调用基准值左边quick_sort(p_num, left - p_num);quick_sort(right + 1,size - 1 - (left - p_num));}int main()
{int arr[5] = {5, 2, 1, 3, 4 };bubble_sort(arr, 5);for(int i = 0; i < 5; i++){cout << arr[i] << " ";}cout << endl;int arr1[5] = { 2, 0, 1,3, 4 };select_sort(arr1, 5);for(int i = 0; i < 5; i++){cout << arr1[i] << " ";}cout << endl;int arr2[5] = { 2, 6, 5, 3, 4 };insertionSort(arr2, 5);for(int i = 0; i < 5; i++){cout << arr2[i] << " ";}cout << endl;int arr3[5] = { 7, 6, 10, 8, 9 };quick_sort(arr3, 5);for(int i = 0; i < 5; i++){cout << arr3[i] << " ";}cout << endl;return 0;
}
  • 问题 int *temp == nullptr不能存储元素

    temp是一个指针,它用于存储内存地址。在你的代码中,你试图用 *temp 来存储交换的值,
    但 temp 没有指向一个有效的内存地址,所以这种操作是非法的。这就像你有一个指向空房间的门(指针),但你却试图把东西放进这个不存在的房间里2 查找

2 查找

查找算法是计算机科学中用于在数据结构中查找特定元素的算法。

  • 二分查找

    有序数组中,通过不断将数组分成两半,比较中间元素与目标值的大小,从而确定下一步的查找范 围。

    示例 时间复杂度O(log n)在这里插入图片描述

    在这里插入图片描述

    在这里插入图片描述

    int* half_search(const int *p_num, int size, int num)
    {// 开始位置const int *p_start = p_num;// 结束位置const int* p_end = p_num + size - 1;// 中间位置const int* p_mid = nullptr;while (p_start <= p_end){// 中间位置就是开始位置加(结束位置 -开始位置) /2p_mid  = p_start + (p_end - p_start ) / 2 ;          if ( *p_mid ==  num){    return (int*)p_mid;}//中间值比要找的值小else if( *p_mid < num  ){      //在后半部分找p_start = p_mid + 1;}//中间值比要找的值大else {//在前半部分找p_end = p_mid - 1;}}
    // 遍历完了没有return nullptr;
    }
    int main()
    {int arr[5] = {1, 2, 3, 4, 5 };int *p = half_search(arr3, 5 , 4);cout << *p << " ";return 0;
    }
    

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

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

相关文章

【Spark】-- DAG 和宽窄依赖的核心

目录 Spark DAG 和宽窄依赖的核心 一、什么是 DAG? 示例:WordCount 程序的 DAG 二、宽依赖与窄依赖 1. 窄依赖 2. 宽依赖 三、DAG 与宽窄依赖的性能优化 1. 减少 Shuffle 操作 2. 合理划分 Stage 3. 使用缓存机制 四、实际案例分析:同行车判断 五、总结 Spark D…

C#中UI线程的切换与后台线程的使用

文章速览 UI线程切换示例 后台线程使用示例 两者对比适用场景Application.Current.Dispatcher.InvokeTask.Factory.StartNew 执行同步性Application.Current.Dispatcher.InvokeTask.Factory.StartNew 一个赞&#xff0c;专属于你的足迹&#xff01; UI线程切换 在WPF应用程序…

【HTML】个人博客页面

目录 页面视图​编辑 页面代码 解释&#xff1a; HTML (<body>): 使用了更加语义化的HTML5标签&#xff0c;例如<header>, <main>, <article>, <footer>。文章列表使用了<article>包裹&#xff0c;结构清晰。添加了分页导航。使用了Font…

第J1周:ResNet-50算法实战与解析

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客 &#x1f356; 原作者&#xff1a;K同学啊 我的环境 语言环境:Python3.8 编译器:Jupyter Lab 深度学习环境:Pytorchtorch1.12.1cu113 torchvision0.13.1cu113 一、准备工作 二、导入数据 三、划分数据…

养生:健康生活的极简攻略

在追求高效生活的当下&#xff0c;养生也能化繁为简。通过饮食、运动、睡眠与心态的精准调节&#xff0c;就能轻松为健康续航。 饮食上&#xff0c;遵循 “均衡、节制” 原则。早餐用一杯热豆浆搭配水煮蛋和半个苹果&#xff0c;唤醒肠胃活力&#xff1b;午餐以糙米饭为主食&am…

迁移 Visual Studio Code 设置和扩展到 VSCodium

本文同步发布在个人博客 迁移 Visual Studio Code 设置和扩展到 VSCodium - 萑澈的寒舍https://hs.cnies.org/archives/vscodium-migrateVisual Studio Code&#xff08;以下简称 VS Code&#xff09;无疑是当下最常用的代码编辑器。尽管微软的 VS Code 源代码采用 MIT 协议开…

力扣654题:最大二叉树(递归)

小学生一枚&#xff0c;自学信奥中&#xff0c;没参加培训机构&#xff0c;所以命名不规范、代码不优美是在所难免的&#xff0c;欢迎指正。 标签&#xff1a; 二叉树、递归 语言&#xff1a; C 题目&#xff1a; 给定一个不重复的整数数组 nums 。最大二叉树可以用下面的算…

离散制造企业WMS+MES+QMS+条码管理系统高保真原型全解析

在离散型制造企业的生产过程中&#xff0c;库存管理混乱、生产进度不透明、质检流程繁琐等问题常常成为制约企业发展的瓶颈。为了帮助企业实现全流程数字化管控&#xff0c;我们精心打造了一款基于离散型制造企业&#xff08;涵盖单件生产、批量生产、混合生产模式&#xff09;…

Linux操作系统--进程间通信(system V共享内存)

目录 1.system V共享内存 2.共享内存数据结构 3.共享内存函数 4.实例代码&#xff1a; 1.system V共享内存 共享内存区是最快的IPC(进程间通信)形式。一旦这样的内存映射到共享它的进程地址空间&#xff0c;这些进程间数据传递不再涉及到内核&#xff0c;换句话说是进程不再…

【C++】类与对象

目录 1、类的定义 2、类的访问限定符及封装 3、类的实例化 4、类和对象的大小 5、this 指针 6、类的六个默认成员函数 构造函数 析构函数 拷贝构造函数 赋值重载函数 取地址运算符的重载函数 7、运算符重载 8、const 成员函数 9、 static 成员 10、友元 11、…

现代简约中式通用,民国画报风,中国风PPT模版8套一组分享

中国风PPT模版分享&#xff1a;中国风PPT模版分享https://pan.quark.cn/s/abbf75507c5f 第1套PPT模版&#xff1a;棕色调中式窗棂封面&#xff0c;水墨山水背景配白梅与灯笼流苏&#xff0c;适用于教学课件目录设计&#xff0c;展现浓郁的书卷气息。 第2套PPT模版&#xff1a;米…

django扩展练习记录

一、Django 中使用 django-apscheduler 实现定时任务 可以方便地管理周期性任务&#xff08;如每天清理缓存、定时发送邮件等&#xff09; 1. 安装 pip install django-apscheduler -i https://pypi.tuna.tsinghua.edu.cn/simple #0.7.02.添加到应用&#xff0c;python m…

Guided Filtering相关记录

一、背景介绍 以前折腾保边滤波时候&#xff0c;刷了一些Guided Filtering相关资料。这里主要是对它们做个算法效果复现和资料简单整理。 二、Guided Filtering 1、基本原理 原版Guided Filtering的提出&#xff0c;主要是为了改善双边滤波做保边平滑滤波器时候的梯度翻转伪影…

知识图谱系列(2):知识图谱的技术架构与组成要素

1. 引言 知识图谱作为一种强大的知识表示和组织方式,已经在搜索引擎、推荐系统、智能问答等多个领域展现出巨大的价值。在之前的上一篇文章中,我们介绍了知识图谱的基础概念与发展历程,了解了知识图谱的定义、核心特征、发展历史以及在AI发展中的地位与作用。 要深入理解和…

操作系统|| 虚拟内存页置换算法

题目 写一个程序来实现 FIFO 和 LRU 页置换算法。首先&#xff0c;产生一个随机的页面引用序列&#xff0c;页面数从 0~9。将这个序列应用到每个算法并记录发生的页错误的次数。实现这个算法时要将页帧的数量设为可变。假设使用请求调页。可以参考所示的抽象类。 抽象类&…

开发与AI融合的Windsurf编辑器

Windsurf编辑器是开发人员和人工智能真正融合在一起的地方&#xff0c;提供了一种感觉像文字魔术的编码体验。 手册&#xff1a;Windsurf - Getting Started 下载链接&#xff1a;Download Windsurf Editor for Windows | Windsurf (formerly Codeium) 下载安装 从上面的下载…

【Java】网络编程(Socket)

网络编程 Socket 我们开发的网络应用程序位于应用层&#xff0c;TCP和UDP属于传输层协议&#xff0c;在应用层如何使用传输层的服务呢&#xff1f;在应用层和传输层之间&#xff0c;则使用套接字Socket来进行分离 套接字就像是传输层为应用层开的一个小口&#xff0c;应用程…

【教程】Docker方式本地部署Overleaf

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhagn.cn] 如果本文帮助到了你&#xff0c;欢迎[点赞、收藏、关注]哦~ 目录 背景说明 下载仓库 初始化配置 修改监听IP和端口 自定义网站名称 修改数据存放位置 更换Docker源 更换Docker存储位置 启动Overleaf 创…

根据用户ID获取所有子节点数据或是上级直属节点数据

一、根据用户ID获取所有子节点&#xff0c;通过存储过程来实现 CREATE DEFINERcrmeb% PROCEDURE proc_get_user_all_children( IN rootUid INTEGER, -- 要查询的根用户ID IN includeSelf BOOLEAN -- 是否包含自身(1包含,0不包含) ) BEGIN -- 声明变…

计算机组成原理——数据的表示

2.1数据的表示 整理自Beokayy_ 1.进制转换 十六进制与二进制的转换 一位十六进制等于四位二进制 四位二进制等于一位十六进制 0x173A4C0001 0111 0011 1010 0100 1100 十六进制与十进制的转换 十六转十&#xff1a;每一位数字乘以相应的16的幂再相加 十转十六&#xff1a…