八种常见顺序存储的算法

目录

1、线性枚举

1)问题描述

2)动图演示

3)示例说明

4)算法描述

5)源码详解

2、前缀和差分

1)问题描述

2)动图演示

3)样例分析

4)算法描述

5)源码详解

3、双指针

1)问题描述

2)动图演示

3)样例说明

4)算法描述

5)源码详解

4、二分枚举

1)问题描述​编辑

2)动图演示

3)样例说明

4)算法描述

5)源码详解

5、三分枚举

6、插入排序

1)问题描述

2)动图演示

3)样例说明

4)算法描述

5)源码详解

7、选择排序

1)问题描述

2)动图演示

3)样例说明

4)算法描述

5)源码详解

8、冒泡排序

1)问题描述

2)动图演示

3)样例说明

4)算法描述

5)源码详解


1、线性枚举

1)问题描述

2)动图演示

3)示例说明

  蓝色的数据代表的是数组数据,红色的数据代表当前枚举到的数据,这样就可以遍历所有的数据进行逻辑处理了。

4)算法描述

  遍历数组,进行条件判断,条件满足则执行逻辑。这里的条件就是 枚举到的数 是否小于 当前最小值,执行逻辑为 将 当前枚举到的数 赋值给 当前最小值

5)源码详解

int findMin(int* nums, int numsSize){int i, min = 100000;for(i = 0; i < numsSize; ++i) {     // (1)if(nums[i] < min) {             // (2)min = nums[i];}}return min;                         // (3)
}

  • (1) 遍历数组中所有的数;
  • (2) 如果 当前枚举到的数 比记录的变量min小,则将它赋值给min;否则,不做任何处理;
  • (3) 最后,min中存储的就是整个数组的最小值。

2、前缀和差分

1)问题描述

2)动图演示

3)样例分析

  如上图所示,只需要记录一个前缀和,然后就可以通过一次减法将区间的值计算出来。时间复杂度 O(1)。这种就是差分的思想。

原理:

sum[r] = a[1] + a[2] + a[3] + a[l-1] + a[l] + a[l + 1] ...... a[r];

sum[l - 1] = a[1] + a[2] + a[3] + a[l - 1];

sum[r] - sum[l - 1] = a[l] + a[l + 1] + ......+ a[r];

4)算法描述

  第一个枚举,利用一个数组sum,存储前 i 个元素的和。
  第二个枚举,读入 m 组数据 l,r,对每组数据,通过 O(1) 获取答案,即
sum[r] - sum[l - 1]​。

5)源码详解

int sum[maxn];
int* prefixSum(int* nums, int numsSize, int m, int *l, int *r){int i;int *ret;for(i = 0; i < numsSize; ++i) {sum[i] = nums[i];if(i) sum[i] += sum[i-1];                 // (1) }ret = (int *) malloc( m * sizeof(int) );    // (2) for(i = 0; i < m; ++i) {int leftsum = l[i] == 0 ? 0 : sum[l[i]-1]; // (3) int rightsum = sum[r[i]];ret[i] = rightsum - leftsum;            // (4) }return ret;
}

  • (1) 计算前缀和;
  • (2) 需要返回的数组;
  • (3) 这里是为了防止数组下标越界;
  • (4) 核心 O(1) 的差分计算;

3、双指针

1)问题描述

2)动图演示

3)样例说明

  维护两个指针 i 和 j,区间 [i,j] 内的子串,应该时刻保持其中所有字符不重复,一旦发现重复字符,就需要自增 i(即执行 i = i + 1);否则,执行 j = j + 1,直到 j 不能再增加为止。
  过程中,记录合法情况下 j − i + 1 的最大值。

4)算法描述

  如上文所述,这种利用问题特性,通过两个指针,不断调整区间,从而求出问题最优解的算法就叫 “尺取法”,由于利用的是两个指针,所以又叫 “双指针” 算法。
  这里 “尺” 的含义,主要还是因为这类问题,最终要求解的都是连续的序列(子串),就好比一把尺子一样,故而得名。

算法描述如下:
  1)初始化 i = 0, j = i − 1,代表一开始 “尺子” 的长度为 0;
  2)增加 “尺子” 的长度,即 j = j + 1;
  3)判断当前这把 “尺子” [i,j] 是否满足题目给出的条件:
    3.a)如果不满足,则减小 “尺子” 长度,即 i = i + 1,回到 3);
    3.b)如果满足,记录最优解,回到 2);

  • 上面这段文字描述的比较官方,其实这个算法的核心,只有一句话:

    满足条件时,j++;不满足条件时,i++;

  • 如图所示,当区间 [i,j] 满足条件时,用蓝色表示,此时 j 自增;反之闪红,此时 i 自增。
    在这里插入图片描述

5)源码详解

int getmaxlen(int n, char *str, int& l, int& r) {int ans = 0, i = 0, j = -1, len;   // 1)memset(h, 0, sizeof(h));           // 2)while (j++ < n - 1) {              // 3)++h[ str[j] ];                 // 4)while (h[ str[j] ] > 1) {      // 5)--h[ str[i] ];++i;}len = j - i + 1;              if(len > ans)                  // 6)ans = len, l = i, r = j;}return ans;
}

  • 1)初始化 i = 0, j = -1,代表 s[i:j] 为一个空串,从空串开始枚举;
  • 2)需要维护一个哈希表,哈希表记录的是当前枚举的区间 s[i:j] 中每个字符的个数;
  • 3)只推进子串的右端点;
  • 4)在哈希表中记录字符的个数;
  • 5)当 h[ str[j] ] > 1满足时,代表出现了重复字符str[j],这时候左端点 i 推进,直到没有重复字符为止;
  • 6)记录当前最优解的长度 j - i + 1,更新;
  • 这个算法执行完毕,我们就可以得到最长不重复子串的长度为 ans,并且 i 和 j 这两个指针分别只自增 n 次,两者自增相互独立,是一个相加而非相乘的关系,所以这个算法的时间复杂度为 O(n) 。

4、二分枚举

1)问题描述

2)动图演示

3)样例说明

  需要找值为 5 的这个元素。
  黄色箭头代表都是左区间端点 l,红色箭头代表右区间端点 r。蓝色的数据为数组数据,绿色的数字代表的是数组下标,初始化 l = 0,r = 7,由于数组有序,则可以直接折半,令 mid =(l+r)/2=3,则 55 一定落入区间 [0,3],这时候令 r = 3,继续执行,直到 l > r 结束迭代。
  最后,当 mid = 2 时,找到数据 5。

4)算法描述

  a)令初始情况下,数组下标从 0 开始,且数组长度为 n,则定义一个区间,它的左端点是      l = 0,右端点是 r = n−1;
  b)生成一个区间中点 mid = (l+r)/2,并且判断 mid 对应的数组元素和给定的目标值的大小关系,主要有三种:
    b.1)目标值 等于 数组元素,直接返回 mid;
    b.2)目标值 大于 数组元素,则代表目标值应该出现在区间 [mid+1,r],迭代左区间端点:l=mid+1;
    b.3)目标值 小于 数组元素,则代表目标值应该出现在区间 [l,mid−1],迭代右区间端点:r=mid−1;
  c)如果这时候 l>r,则说明没有找到目标值,返回 −1;否则,回到 b)继续迭代。

5)源码详解

int search(int *nums, int numsSize, int target) {int l = 0, r = numsSize - 1;         // (1)while(l <= r) {                      // (2)int mid = (l + r) >> 1;          // (3)if(nums[mid] == target) {   return mid;                  // (4)}else if(target > nums[mid]) {l = mid + 1;                 // (5)}else if(target < nums[mid]) {r = mid - 1;                 // (6)}}return -1;                           // (7)
}

  • (1) 初始化区间左右端点;
  • (2) 一直迭代左右区间的端点,直到 左端点 大于 右端点 结束;
  • (3) >> 1等价于除 2,也就是这里mid代表的是lr的中点;
  • (4) nums[mid] == target表示正好找到了这个数,则直接返回下标mid
  • (5) target > nums[mid]表示target这个数在区间 [���+1,�][mid+1,r] 中,所以才有左区间赋值如下:l = mid + 1;
  • (6) target < nums[mid]表示target这个数在区间 [�,���−1][l,mid−1] 中,所以才有右区间赋值如下:r = mid - 1;
  • (7) 这一步呼应了 (2),表示这不到给定的数,直接返回 -1

5、三分枚举

  三分枚举 类似 二分枚举 的思想,也是将区间一下子砍掉一块基本完全不可能的块,从而减小算法的时间复杂度。只不过 二分枚举 解决的是 单调性 问题。而 三分枚举 解决的是 极值问题。

6、插入排序

1)问题描述

  给定一个 n 个元素的数组,数组下标从 0 开始,采用「 插入排序 」将数组按照 「升序」排列。

2)动图演示

3)样例说明

图示含义
蓝色柱形代表尚未排好序的数
绿色柱形代表正在执行 比较 和 移动 的数
橙色柱形代表已经排好序的数
红色柱形代表待执行插入的数

  我们看到,首先需要将 「第二个元素」 和 「第一个元素」 进行 「比较」,如果 前者 小于等于 后者,则将 后者 进行向后 「移动」前者 则执行插入;
  然后,进行第二轮「比较」,即 「第三个元素」 和 「第二个元素」、「第一个元素」 进行 「比较」, 直到 「前三个元素」 保持有序 。
  最后,经过一定轮次的「比较」 和 「移动」之后,一定可以保证所有元素都是 「升序」 排列的。

4)算法描述

整个算法的执行过程分以下几步:
  1) 循环迭代变量 i=1→n−1;
  2) 每次迭代,令 x=a[i],j=i−1,循环执行比较 x 和 a[j],如果产生 x≤a[j] 则执 行 a[j+1]=a[j]。然后执行j=j+1,继续执行 2);否则,跳出循环,回到 1)

5)源码详解

#include <stdio.h>int a[1010];void Input(int n, int *a) {for(int i = 0; i < n; ++i) {scanf("%d", &a[i]);}
}void Output(int n, int *a) {for(int i = 0; i < n; ++i) {if(i)printf(" ");printf("%d", a[i]);}puts("");
}void InsertSort(int n, int *a) {       // (1)int i, j; for(i = 1; i < n; ++i) {int x = a[i];                  // (2)for(j = i-1; j >= 0; --j) {    // (3)if(x <= a[j]) {            // (4)a[j+1] = a[j];         // (5)}elsebreak;                 // (6)}a[j+1] = x;                    // (7)}
} int main() {int n;while(scanf("%d", &n) != EOF) {Input(n, a);InsertSort(n, a);Output(n, a);}return 0;
} 

  • (1) void InsertSort(int n, int *a)为 插入排序 的实现,代表对a[]数组进行升序排序。
  • (2) 此时a[i]前面的 i-1个数都认为是排好序的,令x = a[i]
  • (3) 逆序的枚举所有的已经排好序的数;
  • (4) 如果枚举到的数a[j]比需要插入的数x大,则当前数往后挪一个位置;
  • (5) 执行挪位置的 �(1)O(1) 操作;
  • (6) 否则,跳出循环;
  • (7) 将x插入到合适位置;

7、选择排序

1)问题描述

  给定一个 �n 个元素的数组,数组下标从 00 开始,采用「 选择排序 」将数组按照 「升序」排列。

2)动图演示

3)样例说明

图示含义
蓝色柱形代表尚未排好序的数
绿色柱形代表正在执行 比较 的数
橙色柱形代表已经排好序的数
红色柱形有两种:1、记录最小元素 2、执行交换的元素

  我们发现,首先从 「第一个元素」 到 「最后一个元素」 中选择出一个 「最小的元素」,和 「第一个元素」 进行 「交换」
  然后,从 「第二个元素」 到 「最后一个元素」 中选择出一个 「最小的元素」,和 「第二个元素」 进行 「交换」
  最后,一定可以保证所有元素都是 「升序」 排列的。

4)算法描述

整个算法的执行过程分以下几步:
  1) 循环迭代变量 i=0→n−1;
  2) 每次迭代,令 min=i,j=i+1;
  3) 循环执行比较 a[j] 和 a[min],如果产生 a[j]<a[min] 则执行 min=j。执行 j=j+1,继续执行这一步,直到 j==n;
  4) 交换 a[i] 和 a[min],回到 1)

5)源码详解

#include <stdio.h>int a[1010];void Input(int n, int *a) {for(int i = 0; i < n; ++i) {scanf("%d", &a[i]);}
}void Output(int n, int *a) {for(int i = 0; i < n; ++i) {if(i)printf(" ");printf("%d", a[i]);}puts("");
}void Swap(int *a, int *b) {int tmp = *a;*a = *b;*b = tmp;
}void SelectionSort(int n, int *a) {  // (1)int i, j;for(i = 0; i < n - 1; ++i) {     // (2)int min = i;                 // (3)for(j = i+1; j < n; ++j) {   // (4)if(a[j] < a[min]) {min = j;             // (5)}}Swap(&a[i], &a[min]);        // (6) }
}int main() {int n;while(scanf("%d", &n) != EOF) {Input(n, a);SelectionSort(n, a);Output(n, a);}return 0;
} 

  • (1) void SelectionSort(int n, int *a)为选择排序的实现,代表对a[]数组进行升序排序。
  • (2) 从首元素个元素开始进行 n−1 次跌迭代。
  • (3) 首先,记录min代表当前第 i 轮迭代的最小元素的下标为 i。
  • (4) 然后,迭代枚举第 i+1 个元素到 最后的元素。
  • (5) 选择一个最小的元素,并且存储下标到 min中。
  • (6) 将 第 i 个元素 和 最小的元素 进行交换。

8、冒泡排序

1)问题描述

  给定一个 n 个元素的数组,数组下标从 0 开始,采用「 冒泡排序 」将数组按照 「升序」排列。

2)动图演示

3)样例说明

图示含义
蓝色柱形代表尚未排好序的数
绿色柱形代表正在执行比较的两个数
黄色柱形代表已经排好序的数

  我们看到,首先需要将 「第一个元素」 和 「第二个元素」 进行 「比较」,如果 前者 大于 后者,则进行 「交换」,然后再比较 「第二个元素」 和 「第三个元素」 ,以此类推,直到 「最大的那个元素」 被移动到 「最后的位置」 。
  然后,进行第二轮「比较」,直到 「次大的那个元素」 被移动到 「倒数第二的位置」 。
  最后,经过一定轮次的「比较」 和 「交换」之后,一定可以保证所有元素都是 「升序」 排列的。

4)算法描述

整个算法的执行过程分以下几步:
  1) 循环迭代变量 i=0→n−1;
  2) 每次迭代,令 j=i,循环执行比较 a[j] 和 a[j+1],如果产生 a[j]>a[j+1] 则交换两者的值。然后执行 j=j+1,这时候对 j 进行判断,如果 j≥n−1,则回到 1),否则继续执行 2)

5)源码详解

#include <stdio.h>int a[1010];void Input(int n, int *a) {for(int i = 0; i < n; ++i) {scanf("%d", &a[i]);}
}void Output(int n, int *a) {for(int i = 0; i < n; ++i) {if(i)printf(" ");printf("%d", a[i]);}puts("");
}void Swap(int *a, int *b) {int tmp = *a;*a = *b;*b = tmp;
}void BubbleSort(int n, int *a) {             // (1)bool swapped;int last = n;do {swapped = false;                     // (2)for(int i = 0; i < last - 1; ++i) {  // (3)if(a[i] > a[i+1]) {              // (4)Swap(&a[i], &a[i+1]);        // (5)swapped = true;              // (6)}}--last;}while (swapped);
} int main() {int n;while(scanf("%d", &n) != EOF) {Input(n, a);BubbleSort(n, a);Output(n, a);}return 0;
} 

  • (1) void BubbleSort(int n, int *a)为冒泡排序的实现,代表对a[]数组进行升序排序。
  • (2) swapped标记本轮迭代下来,是否有元素产生了交换。
  • (3) 每次冒泡的结果,会执行last的自减,所以待排序的元素会越来越少。
  • (4) 如果发现两个相邻元素产生逆序,则将它们进行交换。保证右边的元素一定不比左边的小。
  • (5) swap实现了元素的交换,这里需要用&转换成地址作为传参。
  • (6) 标记更新。一旦标记更新,则代表进行了交换,所以下次迭代必须继续。

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

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

相关文章

Flink Kafka[输入/输出] Connector

本章重点介绍生产环境中最常用到的Flink kafka connector。使用Flink的同学&#xff0c;一定会很熟悉kafka&#xff0c;它是一个分布式的、分区的、多副本的、 支持高吞吐的、发布订阅消息系统。生产环境环境中也经常会跟kafka进行一些数据的交换&#xff0c;比如利用kafka con…

类。。。。

定义一个person类&#xff0c;包含私有成员&#xff0c;int *age,string &name,一个stu类&#xff0c;包含私有成员double *sore,person p1,写出person类和stu类的特殊成员函数&#xff0c;并写一个stu的函数&#xff0c;显示所有信息。 #include <iostream>using n…

Android下载gradle失败解决方法

1、在gradle-wrapper.properties文件中查看自己需要下载gradle什么版本的包和zip路径&#xff08;wrapper/dists&#xff09;。 2、在setting中查看Gradle的保存路径&#xff0c;如下图&#xff1a;C:/Users/Administrator/.gradle&#xff0c;加上第一步的zip路径得到下载grad…

15 Sequence-Driver-Sequencer communication in UVM

我们分别讨论了sequece_item、sequence、sequencer和driver。在本节中&#xff0c;我们将讨论他们如何相互talk&#xff0c;sequencer如何给driver提供从sequence里的sequence item。在开始阅读本节之前&#xff0c;请确保您了解sequencer和driver中使用的所有方法。&#xff0…

Ubuntu fcitx Install

ubuntu经常出现键盘失灵的问题 查询资料得知应该是Ibus框架的问题 于是需要安装fcitx框架和搜狗拼音 sudo apt update sudo apt install fcitx 设置fcitx开机自启动&#xff08;建议&#xff09; sudo cp /usr/share/applications/fcitx.desktop /etc/xdg/autostart/ 然后…

普中STM32-PZ6806L开发板(HAL库函数实现-TIM2实现us延时)

简介 使用TIM2实现1us延时其他知识 公式 时间&#xff08;s&#xff09;1/时钟频率&#xff08;Hz&#xff09;由导出 1us 1/1M(Hz)预分配设置 系统时钟是72MHz, 要1us的延时, 预分配得设置为72-1计数器重载设置 设置为最大值65535&#xff0c;这样延时的时间可以设置的最…

【Vue3】创建项目的方式

1. 基于 vue-cli 创建 ## 查看vue/cli版本&#xff0c;确保vue/cli版本在4.5.0以上 vue --version## 安装或者升级你的vue/cli npm install -g vue/cli## 执行创建命令 vue create vue_test本质上使用webpack&#xff0c;默认安装以下依赖&#xff1a; 2. 基于 vite 创建 官…

Buck电源设计常见的一些问题(五)MOS管振荡抑制方法(三)

MOS管振荡抑制方法(三)Rboot的选取 1.Rboot的选取2.总结1.Rboot的选取 同步 Buck 变换器一般采用自举电路供电,如图所示。开关节点上升沿的振荡与上管开通关系密切,上管开通时的驱动电流路径如图所示。因此,可以通过增大 Rboot来减缓上管开通的速度,从而抑制开关节点的振…

文献速递:人工智能医学影像分割---高效的MR引导CT网络训练,用于CT图像中前列腺分割

01 文献速递介绍 如今&#xff0c;根据国家癌症研究所的报告&#xff0c;美国约有9.9%的男性患有前列腺癌。1 此外&#xff0c;根据美国癌症协会的数据&#xff0c;预计2019年将有174,650个新病例被诊断出前列腺癌&#xff0c;与此同时大约有31,620名男性将死于前列腺癌。因此…

vue前端预览pdf并加水印、ofd文件,控制打印、下载、另存,vue-pdf的使用方法以及在开发中所踩过的坑合集

根据公司的实际项目需求&#xff0c;要求实现对pdf和ofd文件的预览&#xff0c;并且需要限制用户是否可以下载、打印、另存pdf、ofd文件&#xff0c;如果该用户可以打印、下载需要控制每个用户的下载次数以及可打印的次数。正常的预览pdf很简单&#xff0c;直接调用浏览器的预览…

计算机操作系统(OS)——P1操作系统概述

1、操作系统的概念(定义) 1.1、什么是操作系统 __操作系统&#xff08;Operating System&#xff0c;OS&#xff09;&#xff1a;__是指控制和管理整个计算机系统的__硬件和软件__资源&#xff0c;并合理的组织调度计算机的工作和资源的分配&#xff1b;以__提供给用户和其它…

pytest实现多进程与多线程运行超好用的插件

前言 如果想分布式执行用例&#xff0c;用例设计必须遵循以下原则&#xff1a; 1、用例之间都是独立的&#xff0c; 2、用例a不要去依赖用例b 3、用例执行没先后顺序&#xff0c; 4、随机都能执行每个用例都能独立运行成功每个用例都能重复运行&#xff0c;不影响其它用例 这…

深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第五节 引用类型复制问题及用克隆接口ICloneable修复

深入浅出图解C#堆与栈 C# Heaping VS Stacking 第五节 引用类型复制问题及用克隆接口ICloneable修复 [深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第一节 理解堆与栈](https://mp.csdn.net/mdeditor/101021023)[深入浅出图解C#堆与栈 C# Heap(ing) VS Stack(ing) 第二节…

九九乘法表c 语言 用于打印九九乘法表

以下是一个简单的C语言程序&#xff0c;用于打印九九乘法表&#xff1a; #include <stdio.h>int main() {int i, j;for (i 1; i < 9; i) {for (j 1; j < i; j) {printf("%d*%d%-2d ", j, i, i*j);}printf("\n");}return 0; }解释&#xff1…

JavaScript练习题第(四)部分

大家好关于JavaScript基础知识点已经发布&#xff1a;需要的大家可以去我的主要查看 &#xff08;当然了有任何不会的&#xff0c;可以私信我&#xff01;&#xff01;&#xff01;&#xff01;&#xff09; 为了巩固大家学习知识点给大家准备几道练习题&#xff1a; 当然&…

网络编程『简易TCP网络程序』

&#x1f52d;个人主页&#xff1a; 北 海 &#x1f6dc;所属专栏&#xff1a; Linux学习之旅、神奇的网络世界 &#x1f4bb;操作环境&#xff1a; CentOS 7.6 阿里云远程服务器 文章目录 &#x1f324;️前言&#x1f326;️正文TCP网络程序1.字符串回响1.1.核心功能1.2.程序…

CGAL的D维包围盒相交计算

包围盒相交测试是一种用于快速判断两个三维对象是否相交的方法&#xff0c;而AABB树则是一种数据结构&#xff0c;常用于加速场景中的射线检测和碰撞检测。 首先&#xff0c;让我们了解一下包围盒相交测试。这种测试的目的是为了快速判断两个三维对象是否相交&#xff0c;而不需…

同化的题解

时间限制: 1000ms 空间限制: 524288kB 题目描述 古人云&#xff1a;“近朱者赤近墨者黑”。这句话是很有道理的。这不鱼大大和一群苦命打工仔被安排进厂拧螺丝了。 进厂第一天&#xff0c;每个人拧螺丝的动力k都是不同且十分高涨的。但是当大家坐在一起后会聊天偷懒&#xf…

在微服务中如何实现全链路的金丝雀发布?

目录 1. 什么金丝雀发布&#xff1f;它有什么用&#xff1f; 2.如何实现全链路的金丝雀发布 2.1 负载均衡模块 2.2 网关模块 2.3 服务模块 2.3.1 注册为灰色服务实例 2.3.2 设置负载均衡器 2.3.3 传递灰度发布标签 2.4 其他代码 2.4.1 其他业务代码 2.4.2 pom.xml 关…

CSS 向上扩展动画

上干货 <template><!-- mouseenter"startAnimation" 表示在鼠标进入元素时触发 startAnimation 方法。mouseleave"stopAnimation" 表示在鼠标离开元素时触发 stopAnimation 方法。 --><!-- 容器元素 --><div class"container&q…