算法回忆录——排序

文章目录

  • 1. 插入排序
  • 2. 选择排序
  • 3. 冒泡排序
  • 4. 希尔排序
  • 5. 归并排序
  • 6. 快速排序
  • 7. 堆排序
  • 8. 计数排序
  • 9. 桶排序
  • 10. 基数排序

1. 插入排序

分为两个序列,前面一个序列是排好序的,后面一个序列是未排好的。未排好的序列的第一个元素(a)从后往前去和排好序的序列的元素(b)挨个比较。若a<b,就需将b往后移一位(需要提前用一个变量存储a的值)。然后继续比较,那么就会有两种情况:1. 比较到a>b时停止,此时a停留的下标就在b的后一个,也就是a要占据的位置。2. 比较到最后也没有比a小的b,此时a就应该占据该有序序列的第一个位置。

a = [21,3,10,33,9,22,34,18,26,15,100,2,11,31,52]for i in range(1, len(a)):# i表示未排好的序列的第一个元素的下标# j表示已排好的序列的最后一个元素的下标j = i - 1# 开始将a[i]与已排好的序列进行比较while j >= 0:# 如果小于if a[i] < a[j]:# 下标减一继续往前比较j -= 1else:# 如果a[i] > a[j],则可以终止循环了break# 循环结束时的j表示a[i]>a[j]的那个j,所以a[i]要放入的位置应该在a[j]的后面# 或者说循环结束时一直没有找到比a[i]小的a[j],此时j为-1,应当放入最前面j += 1# 将a[i]存储起来b = a[i]# 然后将已排好的序列从j的位置开始,整体往后移一位for n in range(i, j, -1):a[n] = a[n - 1]# 最后再在j处放上a[i]a[j] = bprint(a)

改进:可以不用在找到插入位置的时候再挨个往后移,可以先将a[i]存储起来,在与排好的序列挨个比较时就开始往后移。

a = [21, 3, 10, 33, 9, 22, 34, 18, 26, 15, 100, 2, 11, 31, 100, 52]for i in range(0, len(a) - 1):# 排好序列的最后一个元素的下标end = i# 存储好当前未排元素wait = a[end + 1]# 将该未排元素开始依次从后往前与排好的元素比较while end >= 0:# 如果该未排元素小于当前已排好的元素,就将当前已排好元素往后移if wait < a[end]:a[end + 1] = a[end]end -= 1else:breaka[end + 1] = waitprint(a)

2. 选择排序

先找到最小的元素,与原序列第一个元素交换,然后再去排除第一个元素的序列中找到最小的,与原序列中第二个元素交换…

a = [21,3,10,33,9,22,34,18,26,15,100,2,11,31,52]def select_sort(a, n):# 依次从未排序的序列中找到最小的元素的下标for i in range(n):pos = i# 用原序列第一个元素去跟剩下元素比较,找到最小的元素,然后记录下标for j in range(i + 1, n):if a[j] < a[pos]:pos = j# 此时已经找到最小元素的下标,与原序列第一个元素交换位置a[i], a[pos] = a[pos], a[i]return a
print(select_sort(a, len(a)))

3. 冒泡排序

冒泡排序就是将一个数与其它数挨个比较,在比较的过程中,始终是小的数在前面,大的数在后面,这样不断比较和交换,大的数就挨个排到后面去了。

a = [21,3,10,33,9,22,34,18,26,15,100,2,11,31,52]def bubble_sort(a, n):for i in range(n):for j in range(n - 1):if a[j + 1] < a[j]:a[j], a[j + 1] = a[j + 1], a[j]return a
print(bubble_sort(a, len(a)))

4. 希尔排序

希尔排序也算是一种插入排序,不过它是按照某种规则进行分组后,在每个组内进行插入排序。

分组主要就是靠**“增量”**来划分。增量的取值又很多种,普遍简单的是以第一个增量为,数组长度的一半(向下取整),第二个增量取第一个增量的一半…最后一个增量一定是1。

那么是如何按照增量分组的呢?

如果以取半的方式来获得增量,那么有增量是多少,就分多少组。

image-20240107163348776

image-20240107163822321

image-20240107164058388

a = [21,3,10,33,9,22,34,18,26,15,100,2,11,31,52]def hill_sort(a, n):# 先取增量为数组长度gap = n# 循环结束的条件,gap=1就是最后一次分组,此时gap/2=0,循环就结束了while gap > 0:# 每次gap取半gap = int(gap / 2)# 增量是多少就有几个组,所以我们需要对每个组进行插入排序for i in range(0, gap):# 对其中一组进行插入排序for j in range(i, n, gap):end = j# 这里需要判断下标是否超出了原数组的长度,其它的操作都是和插入排序一样的if end + gap >= n:breakwait = a[end + gap]while end >= 0:if wait < a[end]:a[end + gap] = a[end]end -= gapelse:breaka[end + gap] = waitreturn aprint(hill_sort(a, len(a)))

下面的代码少了一个循环,就是单独都每个组进行插入排序的那个循环。

a = [21,3,10,33,9,22,34,18,26,15,100,2,11,31,52]def hill_sort(a, n):gap = nwhile gap > 0:gap = int(gap / 2)for i in range(0, n):end = iif end + gap >= n:continuewait = a[end + gap]while end >= 0:if wait < a[end]:a[end + gap] = a[end]end -= gapelse:breaka[end + gap] = waitreturn aprint(hill_sort(a, len(a)))

5. 归并排序

归并排序采用分治策略,即将一个序列拆分成许多小序列进行排序,就是将排好序的小序列合起来再进行排序。

在这里插入图片描述

有两种实现方式:递归和迭代

  • 递归:实现递归的时候不要多想,假设递归一次就成功。
a = [21,3,10,33,9,22,34,18,26,15,100,2,11,31,52]def merge_sort(a):# 数组长度n = len(a)# 递归终止条件。当数组不断被拆分,直至只剩一个元素时,递归就终止,开始一层一层地从里往外计算。if n <= 1:return a# 向下取整,如果数组是奇数大小,那么左边部分一定比右边部分小1mid = int(n / 2)# 拆分后将左边和右边部分分别进行递归# 其实就只有这里需要递归,所以这里写好后就不要去考虑一层一层嵌套的问题了left = merge_sort(a[:mid])right = merge_sort(a[mid:])# 用来存放“治”后的数组,也就是将两个数组中的元素按从小到大的顺序依次放入sort中sort = []i, j = len(left), len(right)# 这里是假设两个数组都有元素的情况,若其中一个数组元素被弹完了,循环终止while i and j:if left[0] <= right[0]:# 将小的一个添加到sort数组中sort.append(left[0])# 并将这个元素从原数组中弹出left.pop(0)i -= 1else:sort.append(right[0])right.pop(0)j -= 1# 当上面循环结束后只有两种情况:# 1. 两个数组元素都弹完# 2. 一个数组弹完,剩下一个数组未弹完# 那么我就需要将未弹完元素的数组弹尽,同时挨个添加到sort数组中while i:sort.append(left[0])left.pop(0)i -= 1while j:sort.append(right[0])right.pop(0)j -= 1return sortprint(merge_sort(a))
  • 迭代(不会,2024.1.7)

6. 快速排序

快速排序跟冒泡排序很像,都是通过交换两元素位置来排序的。

快速排序需要一个基准元素(通常取数组的第一个元素)和left、right两个左右指针。它就是通过不断将元素与基准元素比较,比基准元素小就放在它的左边,比基准元素大就放在它的右边,然后再让基准元素左边那一段和右边那一段分别进行递归。

left指针一定指向的是数组的左边界(不一定是0)

right指针一定指向的是数组的有边界(不一定是数组的长度-1)

步骤:

  • 判断递归结束的条件
  • 用i和j来代替left和right,边界是固定的,是为了继续向下递归
  • 定义基准元素
  • 开始执行循环比较:
    • 若右指针指向的元素>=基准元素:右指针左移
    • 若右指针指向的元素<=基准元素:右指针指向的元素和左指针指向的元素交换
    • 若左指针指向的元素<=基准元素:左指针右移
    • 若左指针指向的元素>=基准元素:左指针指向的元素和右指针指向的元素交换
arr = [21,3,10,33,9,22,34,18,26,15,100,2,11,31,52]def quick_sort(arr, left, right):# 递归结束条件if left >= right:return# 用i和j分别作为左、右指针来进行移动过# 不能直接用left和right来当作指针,它们是用来当作边界的# left用来规定一段递归的起点,right用来规定另一段递归的终点i = leftj = right# 基准数base = arr[i]# 当左指针始终小于右指针的时候,不断地移动指针和交换指针所指向的元素while i < j:# 如果右指针指向的元素>基准数,右指针左移while i < j and arr[j] >= base:j -= 1# 当上面循环结束时,表示右指针指向的元素小于基准数,将右指针指向的元素与左指针指向的元素交换(只是元素交换位置)arr[j], arr[i] = arr[i], arr[j]# 如果左指针指向的元素<基准数,左指针右移while i < j and arr[i] <= base:i += 1# 当上面循环结束时,表示左指针指向的元素大于基准数,将左指针指向的元素与右指针指向的元素交换arr[i], arr[j] = arr[j], arr[i]# 当上面循环结束后,左指针和右指针一定是相等的quick_sort(arr, left, i - 1)quick_sort(arr, i + 1, right)quick_sort(arr, 0, len(arr) - 1)
print(arr)

7. 堆排序

堆排序本质上还是对数组排序,只是将数组中的元素按树结构的方式排序。

堆本质上也是一棵二叉树。分为大顶堆和小顶堆。大顶堆就是每个根节点的值一定大于等于其左右子节点的值,小顶堆类同。

如何将数组排列成一个堆?

  • 将数组元素依次从上到下,从左到右排列

堆排序一共分为两大步:

  • 将数组排列成一个大顶堆,其中每个根节点都应该满足大顶堆的要求
  • 将堆顶元素与堆中最后一个元素交换,然后将最后一个元素排除在堆外,再重新对这个堆进行大顶堆化。直到排除掉最后一个元素为止

避坑:

  • 最后一个非叶子节点一定是处于length / 2 - 1的位置,它前面的节点也一定有子节点
代码参考:
https://www.hello-algo.com/chapter_sorting/heap_sort/#1171
https://zq99299.github.io/dsalg-tutorial/dsalg-java-hsp/11/01.html#%E5%AE%8C%E6%95%B4%E5%AE%9E%E7%8E%B0
arr = [21,3,10,33,9,22,34,18,26,15,100,2,11,31,52]# 调整堆结构(保持大顶堆)
def adjust_heap(arr, pos, length):"""Args:arr: 要调整的堆(数组)pos: 调整的起始位置(非叶子节点)如果是创建大顶堆,则pos表示的是最下层最右边的那个非叶子节点length: 堆的长度- 如果是创建堆,则length不变- 如果是将根节点元素与堆尾元素交换,则每执行一次length-1Returns:"""while True:# 左子节点的位置l = pos * 2 + 1# 右子节点的位置r = pos * 2 + 2# max表示值最大的节点的位置,在调整之前,假定是根节点的位置max = pos# 如果左子节点的位置(下标)在堆长度范围内且左子节点元素的值大于它的父节点的值if l < length and arr[l] > arr[max]:# max表示的就是左子节点的位置(值更大元素的位置)max = l# 如果右子节点的位置在堆长度范围内且右子节点元素的值大于它的父节点的值if r < length and arr[r] > arr[max]:# max表示的就是右子节点的位置max = r# 如果左右子节点都不大于根节点,max就表示的是根节点的位置,而pos始终都表示根节点的位置,此时就退出循环if max == pos:break# 如果左右子节点有一个大于根节点,则交换两个元素arr[pos], arr[max] = arr[max], arr[pos]# 然后又将交换的那个子节点作为根节点,对它下面的堆继续调整# 因为如果该子节点也是一个堆,它是堆中最大的元素# 但当它的父节点比它小,从而它和父节点交换,此时它的值在它的堆中就不一定是最大的# 另一个子节点自然不用考虑,它肯定是它堆中最大的pos = maxdef heap_sort(arr):# 将数组创建为一个大顶堆for i in range(int(len(arr) / 2) - 1, -1, -1):adjust_heap(arr, i, len(arr))# 交换堆顶元素与堆最后一个元素,然后将最后一个元素排除堆# 将交换后的堆又调整成为一个大顶堆for i in range(len(arr) - 1, 0, -1):arr[0], arr[i] = arr[i], arr[0]adjust_heap(arr, 0, i)heap_sort(arr)
print(arr)

8. 计数排序

计数排序顾名思义就是通过计算arr数组中元素的出现次数来进行排序。

需要额外一个数组来计算arr数组中元素的出现次数。

计数数组的长度为arr数组中最大值(max)-最小值(min)+1。

计数数组的下标区间:[0, max-min+1),当下标区间都加上一个min后:[min, max+1)

右边是开区间是因为数组长度为max-min+1,而数组的下标是从0开始的。

arr = [21,3,10,33,9,22,34,18,26,15,100,2,11,31,52]def counting_sort(arr):# 先获取数组中的最大值和最小值min = arr[0]max = arr[0]for i in range(1, len(arr)):if arr[i] <= min:min = arr[i]if arr[i] >= max:max = arr[i]# 计数用的数组,数组的大小为arr中最大值-最小值+1,该数组的下标就用来表示min到max之间的数counter = [0] * (max - min + 1)# 统计arr数组中每个元素出现的次数for i in range(len(arr)):# counter的下标相当于在一个区间[0, max-min+1],当它的下标加上一个min就表示[min,max]之间的所有数# max-min“+1”是因为下标是从0开始的counter[arr[i] - min] += 1# n用来表示arr中元素的下标n = 0for j in range(len(counter)):# counter数组中的值,就表示它的下标加上min的值这个数出现的次数while counter[j] != 0:arr[n] = j + mincounter[j] -= 1n += 1counting_sort(arr)
print(arr)

9. 桶排序

桶排序就是先确定几个桶,然后将数组中的元素按照某种规则放入桶中,分别对每个桶中的元素进行排序,然后再依次从第一个桶开始将元素拿出来。(后一个桶中的元素的值一定大于前一个桶中元素的值)。

  • 一个桶放几个元素(bucketSize):人为规定或使用默认值
  • 桶数量的确定(bukcetNum):arr数组中的(max - min + 1)/ bucketSize
  • 确定元素放入哪个桶:bucket[(arr[i] - min) / bucketSize]
arr = [21,3,10,33,9,22,34,18,26,15,100,2,11,31,52]def bucket_sort(arr, bucketSize=5):"""Args:arr:bucketSize: 每个桶的容量Returns:"""# 找出arr数组中最大值和最小值max = arr[0]min = arr[0]for i in range(len(arr)):if max < arr[i]:max = arr[i]if min > arr[i]:min = arr[i]# 区间【min,max】一共有max-min+1个数,一个桶装bucketSize个数,所以相除就得到了桶的数量# 最后再加个1是防止前面被除数小于除数,结果就为0个桶,显然是不行的bucketNum = int((max - min + 1) / bucketSize + 1)# 初始化桶bucket = []for j in range(bucketNum):bucket.append([])# 将arr数组中的元素按照范围放入桶中# 可以看到前面桶的数量的定义,要确定放入哪个桶,(arr[i]-min)/bucketSize就能确定桶号for k in range(len(arr)):bucket[int((arr[k] - min) / bucketSize)].append(arr[k])# 桶内进行排序,各种排序方式都行for i in range(len(bucket)):# 这里使用的是前面的快速排序quick_sort(bucket[i], 0, len(bucket[i]) - 1)# 将桶内元素排完序后,从第一个桶开始,依次将桶内元素替换掉arr数组中的元素n = 0for i in range(len(bucket)):if bucket[i]:for j in range(len(bucket[i])):arr[n] = bucket[i][j]n += 1bucket_sort(arr)
print(arr)

10. 基数排序

基数排序是桶排序的拓展,假如排序的数是十进制的,那么每一个数的每一位有10种表示,那么就创建10个桶。

从个位开始,每个数的个位是多少,就放入哪个桶。全部放完后再从第一个桶开始取出来挨个放入原数组,先放进去的先取。

然后从十位开始…

当排序到最后一轮的时候,再取出来放入原数组,这时原数组就有序了。

arr = [21,3,10,33,9,22,34,18,26,15,100,2,11,31,52]def radix_sort(arr):# 找出arr数组中最大的元素max = arr[0]for i in range(len(arr)):if max < arr[i]:max = arr[i]# 得到它的位数sortNum = len(str(max))# 因为是十进制的排序,所以十个桶就行了bucketNum = 10# 初始化桶bucket = []for i in range(bucketNum):bucket.append([])# n是用来辅助求得个位上的数,例如123 / n % 10 = 3      int(123 / (n * 10)) % 10 = 2....n = 1# 最大元素有几位就要进行几次排序for i in range(sortNum):# 初始化桶的计数数组,记录每个桶有多少个元素counter = [0 for j in range(bucketNum)]# 将元素按照它们个位个位、十位等等的数分别放入桶中for k in range(len(arr)):# 得到个位或十位等等上的数d = int(arr[k] / n) % 10# 放入相应的桶中bucket[d].append(arr[k])# 放入一个就加1counter[d] += 1# 指示arr数组元素的位置index = 0# 开始依次将每个桶中的元素取出,从第一个桶开始,先放进去的先出来for m in range(len(counter)):while counter[m] != 0:arr[index] = bucket[m].pop(0)index += 1counter[m] -= 1# 这里一定要记得n *= 10
radix_sort(arr)
print(arr)

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

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

相关文章

Vmware安装Windows11系统及下载MySQL步骤(超详细)

一、创建虚拟机 ①选择自定义 ②直接点击下一步 ③选择Windows 11 x64 ④命名虚拟机以及选择路径 ⑤新版本的虚拟机需要加密&#xff08;密码需要8个字符以上&#xff09; ⑥选择UEFI ⑦处理器配置&#xff08;根据自己的需求&#xff09; ⑧设置虚拟机的内存 ⑨选择不使用网络…

Linux安装JDK和Maven并配置环境变量

文章目录 一、安装JDK并配置环境变量二、安装maven并配置环境变量 一、安装JDK并配置环境变量 将JDK的安装包上传到Linux系统的usr/local目录 使用xftp上传文件 解压JDK的压缩包 xshell连接到云主机 [roottheo ~]# cd /usr/local[roottheo local]# ls aegis apache-tomcat-…

【Docker基础三】Docker安装Redis

下载镜像 根据自己需要下载指定版本镜像&#xff0c;所有版本看这&#xff1a;Index of /releases/ (redis.io) 或 https://hub.docker.com/_/redis # 下载指定版本redis镜像 docker pull redis:7.2.0 # 查看镜像是否下载成功 docker images 创建挂载目录 # 宿主机上创建挂…

2024年跨境电商上半年营销日历,建议收藏

2024年伊始&#xff0c;跨境电商开启新一轮的营销竞技&#xff0c;那么首先需要客户需求&#xff0c;节假日与用户需求息息相关&#xff0c;那么接下来小编为大家整理2024上半年海外都有哪些节日和假期&#xff1f;跨境卖家如何见针对营销日历选品&#xff0c;助力卖家把握2024…

Wrk压测发送Post请求的正确姿势

一、Wrk简介 wrk 是一个能够在单个多核 CPU 上产生显著负载的现代 HTTP 基准测试工具。它采用了多线程设计&#xff0c;并使用了像 epoll 和 kqueue 这样的可扩展事件通知机制。此外&#xff0c;用户可以指定 LuaJIT 脚本来完成 HTTP 请求生成、响应处理和自定义报告等功能。 …

OpenAI ChatGPT-4开发笔记2024-03:Chat之Tool和Tool_Call(含前function call)

Updates on Function Calling were a major highlight at OpenAI DevDay. In another world,原来的function call都不再正常工作了&#xff0c;必须全部重写。 function和function call全部由tool和tool_choice取代。2023年11月之前关于function call的代码都准备翘翘。 干嘛…

CSS 实现两个圆圈重叠部分颜色不同

这是期望实现的效果&#xff0c;由图可知&#xff0c;圆圈底图透明度是0.4&#xff0c;左侧要求重叠部分透明度是0.7&#xff0c;所以不能通过简单的透明度叠加来实现最右侧的效果。 这就需要另外新建一个图层来叠加在两个圆圈重叠上方。 直接看代码 .circle_hight {width: 1…

MySQL深入——9

如何正确的显示随机信息&#xff1f; 我们来模拟在英语单词app当中随机出现三个英语单词的情况&#xff0c;我们首先创建一张表words&#xff0c;然后给这个表当中插入10000条信息进行量化。 select word from words order by rand() limit 3&#xff1b; order by rand&…

外包做了1个月,技术退步一大半了。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;20年通过校招进入深圳某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了四年的功能测试…

一种DevOpts的实现方式:基于gitlab的CICD(二)

写在之前 前文已经搭建了基于gitlab的cicd环境&#xff0c;现在我们来更近一步&#xff0c;结合官网给出的案例来详细介绍如何一步一步实现CI的过程。 基于gitlab搭建一个前端静态页面 环境依赖&#xff1a; gitlabgitlab runner&#xff08;docker版本&#xff09; 环境达吉…

FineBI:简介

1 介绍 FineBI 是帆软软件有限公司推出的一款商业智能&#xff08;Business Intelligence&#xff09;产品。 FineBI 是定位于自助大数据分析的 BI 工具&#xff0c;能够帮助企业的业务人员和数据分析师&#xff0c;开展以问题导向的探索式分析。 2 现阶段数据分析弊端 现阶…

【C/C++】轻量级跨平台 开源串口库 CSerialPort

文章目录 1、简介2、支持的平台3、已经支持的功能4、Linux下使用5、使用vcpkg安装CSerialPort6、交叉编译7、效果图8、基于CSerialPort的应用8.1、CommMaster通信大师8.2、CommLite串口调试器 1、简介 Qt 的QSerialPort 已经是跨平台的解决方案&#xff0c;但Qt开发后端需要 Q…

UE5 将类修改目录

有个需求&#xff0c;需要修改ue里面类的位置&#xff0c;默认在Public类下面&#xff0c;我想创建一个二级目录&#xff0c;将所有的类分好位置&#xff0c;方便查看。 上图为创建一个类所在的默认位置。 接下来&#xff0c;将其移动到一个新的目录中。 首先在资源管理器中找…

Redis高级特性和应用(发布 订阅、Stream)

发布和订阅 Redis提供了基于“发布/订阅”模式的消息机制,此种模式下,消息发布者和订阅者不进行直接通信,发布者客户端向指定的频道( channel)发布消息,订阅该频道的每个客户端都可以收到该消息。 操作命令 Redis主要提供了发布消息、订阅频道、取消订阅以及按照模式订阅和…

HarmonyOS应用开发者基础认证考试

判断题 1.Ability是系统调度应用的最小单元,是能够完成一个独立功能的组件。一个应用可以包含一个或多个Ability。 正确(True) 2.所有使用Component修饰的自定义组件都支持onPageShow,onBackPress和onPageHide生命周期函数。 错误(False) 3.每调用一次router.pushUrl()方法,…

HarmonyOS 应用开发学习笔记 ets组件生命周期

HarmoryOS Ability页面的生命周期 Component自定义组件 ets组件生命周期官放文档 本文讲解 ets组件的生命周期&#xff0c;在此之前大家可以先去了解Ability的生命周期&#xff0c;这两个生命周期有有一定的关联性 在开始之前&#xff0c;我们先明确自定义组件和页面的关系&…

第一个Java网络爬虫程序

目录 前言第一个Java网络爬虫程序总结 前言 网络爬虫是一种获取互联网信息的技术&#xff0c;它可以模拟浏览器行为&#xff0c;访问网站并提取所需的数据。在这个小Demo中&#xff0c;我们使用Java语言结合HttpClient库实现了一个简单的爬虫程序&#xff0c;用于抓取汽车之家…

springCould中的gateway-从小白开始【9】

目录 1.&#x1f35f;网关是什么 2.&#x1f37f;gateway是什么 3.&#x1f95a;gateway能什么 4.&#x1f32d;核心概念 5.&#x1f9c2;工作流程 6.&#x1f9c8;实例 7.&#x1f953;gateway网关配置的方式 8.&#x1f373;配置动态路由 9.&#x1f9c7;pred…

混淆技术概论

混淆技术概论 引言 在逆向工程领域&#xff0c;混淆技术是一种非常重要的技术手段&#xff0c;通过打破人们的思维惯性&#xff0c;使得逆向分析变得更加困难。本文将会介绍混淆技术的概念、分类及其应用&#xff0c;以及如何使用IPA Guard进行iOS IPA重签名。 混淆技术概述…

第四站:C/C++基础-指针

目录 为什么使用指针 函数的值传递&#xff0c;无法通过调用函数&#xff0c;来修改函数的实参 被调用函数需要提供更多的“返回值”给调用函数 减少值传递时带来的额外开销&#xff0c;提高代码执行效率 使用指针前: 使用指针后: 指针的定义: 指针的含义(进阶): 空指针…