13 学习总结:指针 · 其一

目录

一、内存和地址

(一)内存

(二)内存单元

(三)地址

(四)拓展:CPU与内存的联系

二、指针变量和地址

(一)创建变量的本质

(二)取地址操作符:&

(三)指针变量和解引用操作符:*

1、指针变量

2、指针变量的理解

(1)【int* pa】的理解

(2)【int*】的理解

3、解引用操作符:*

(四)指针变量的大小

三、指针变量类型的意义

(一)解引用操作时,决定可以操作多少个字节

(二)指针 + -  整数时,向前/向后走多大的区别

(三)void* 指针

四、const修饰指针

(一)const修饰变量

(二)const修饰指针变量

五、指针的运算

(一)指针 + 或 -  整数

(二)指针 - 指针

(三)指针的关系运算(指针的比较)

六、野指针

(一)野指针造成的原因

1、指针未初始化

2、指针越界访问

3、指针指向的空间释放

(二)如何规避野指针

1、指针初始化

2、小心指针越界

3、指针变量不再使用时,及时置NULL,指针使用之前检查有效性

4、避免返回局部变量的地址

七、assert断言

八、指针的使用和传址调用

(一)指针的使用:strlen的模拟实现

(二)传值调用和传址调用


一、内存和地址

(一)内存

        又称内存储器或主存储器,计算机中所有程序的运行都在内存中进行,计算机上CPU(中央处理器)在处理数据的时候,需要的数据是在内存中读取的,处理后的数据也会放回内存中,这样使用内存则需要高效地管理内存空间;

(二)内存单元

        就是把内存划分为一个个的内存单元,每个内存单元的大小取1个字节(8个比特位),每个内存单元都有⼀个编号,有了这个内存单元的编号,CPU就可以快速找到⼀个内存空间;

(三)地址

        在计算机中我们把【内存单元的编号】也称为【地址】,C语言中给【地址】起了新的名字叫:【指针】

        可以理解为:【内存单元的编号 == 地址 == 指针】

(四)拓展:CPU与内存的联系

        有三条总线将CPU与内存连接彼此,交换数据:①地址总线;②数据总线;③控制总线

        交换过程:地址信息通过【地址总线】被下达给内存,在内存上就可以找到相应的数据,将数据通过【数据总线】传入CPU做处理,【控制总线】则负责传递对数据的操作,如读操作、写操作等

二、指针变量和地址

(一)创建变量的本质

        创建变量的本质是在内存中申请空间,例如创建一个 int 变量就是向内存申请4个字节的空间,每个字节都有自己的编号(地址),变量的名字仅仅是给程序员看的,编译器不看名字,编译器是通过地址找内存单元的

(二)取地址操作符:&

         使用:拿到变量的地址

        例如:

int a = 10;&a;

        &a 就可以拿到变量a的地址,虽然整型变量占用4个字节,我们只要知道了第⼀个字节地址,春藤摸瓜访问到4个字节的数据也是可行的

        注:当一个变量占多个内存单元的时候,总会取出该变量的第一个内存单元(地址较小的那个字节)

(三)指针变量和解引用操作符:*

1、指针变量

        通过取地址操作符(&)拿到的地址是⼀个数值,比如:0x0012ff40,这个数值有时候也是需要存储起来,方便后期再使用的,那我们把这样的地址值存放在哪里呢?答案是:指针变量中,例如:

#include <stdio.h>
int main()
{int a = 10;int * pa = &a;//取出a的地址并存储到指针变量pa中return 0;
}

        指针变量也是⼀种变量,这种变量就是⽤来存放地址的,存放在指针变量中的值都会理解为地址

2、指针变量的理解

        上面例子的写法中的 int *pa 拆开来理解:

(1)【int* pa】的理解

        ①【int *】是变量pa的类型;

        ② pa是一个变量,用来存放地址(指针)的,所以pa又叫指针变量

(2)【int*】的理解

        ① * 表示pa是指针变量;

        ② int 表示【pa 指针变量中保存的地址】所指向的【变量 a】的类型是int

3、解引用操作符:*

        又称为间接访问操作符,用法:

如下演示:
int main()
{int a = 100;int* pa = &a;*pa = 0;此处*pa == a,相当于对a进行修改return 0;
}

        总结:通过【指针变量pa】找到指向的变量a—— *pa(通过pa的值,找到a)

        ① pa —— 指针变量

        ② &pa —— 指针变量pa的地址

        ③ *pa —— pa指向的变量a

(四)指针变量的大小

        【指针变量类型的大小】取决于【地址的大小】,而地址大小由计算机是32位操作系统还是64位操作系统决定

        ① 指针变量是用来存放地址的,一个地址的存放需要多大空间,那么指针变量类型就是多大,所以32位平台总共有32根地址总线,每根线的电信号转化成数字信号后是1或0,那我们把32根地址总线产生的2进制序列作为一个地址,那么一个地址就是32个比特位,就是4个字节;同理,在64位的机器中,一个地址的大小就是8字节

        ② 地址的大小与【指向的原变量的类型大小】无关,就是4字节或者8字节

#include <stdio.h>//指针变量的⼤⼩取决于地址的⼤⼩
//32位平台下地址是32个bit位(即4个字节)
//64位平台下地址是64个bit位(即8个字节)int main()
{printf("%zd\n", sizeof(char *));printf("%zd\n", sizeof(short *));printf("%zd\n", sizeof(int *));printf("%zd\n", sizeof(double *));return 0;
}

        X86环境输出结果如下:

        X64环境输出结果如下:

        结论:

32位平台下地址是32个bit位,指针变量大小是4个字节

64位平台下地址是64个bit位,指针变量大小是8个字节

指针变量的大小和类型是无关的,只要指针类型的变量,在相同的平台下,大小都是相同的

三、指针变量类型的意义

        指针变量的大小和类型无关,只要是指针变量,在同⼀个平台下,大小都是⼀样的,都是4字节或者8字节,为什么还要有各种各样的指针类型呢?

(一)解引用操作时,决定可以操作多少个字节

        如下演示:

#include <stdio.h>
int main()
{int a = 0x11223344;int* p = &a;*p = 0;return 0;
}

        变量a的地址与4个字节的值如下:

        经过 *p = 0;的语句后,4个字节的值全部改为0,如下:

        若代码中指针变量的类型改为char*:

#include <stdio.h>
int main()
{int a = 0x11223344;char* p = &a;*p = 0;return 0;
}

        变量a的地址与4个字节的值如下:

        经过 *p = 0;的语句后,4个字节的值只有一个字节改为0,如下:

      

        结论:指针的类型决定了,解引用操作时,决定可以操作多少个字节

        比如: char* 的指针解引用就只能访问一个字节,而 int* 的指针的解引用就能访问四个字节

(二)指针 + -  整数时,向前/向后走多大的区别

        如下代码演示:

#include <stdio.h>
int main()
{int n = 10;char *pc = (char*)&n;int *pi = &n;printf("%p\n", &n);printf("%p\n", pc);printf("%p\n", pc+1);printf("%p\n", pi);printf("%p\n", pi+1);return 0;
}

        代码结果如下:

        从结果可以得出:char* 类型的指针变量+1跳过1个字节, int* 类型的指针变量+1跳过了4个字节;

        结论:指针的类型决定了指针向前或者向后走一步有多大(距离)           

 补充:
        int* pa;   
        pa+1——> +1 * sizeof (int)
        pa+n——> +n * sizeof (int)

        char* pa;   
        pa+1——> +1 * sizeof (char)
        pa+n——> +n * sizeof (char)

总结:

        类型* 变量名;

        变量名 + 1 ——> +1 * sizeof(指针指向的变量类型)

(三)void* 指针

        void* ——无具体类型的指针(泛型指针)

        可以接收任何类型的地址,但是正因为他是泛型指针,所以没有特定类型指针的用法,即无法解引用和进行指针的 + - 操作

        作用:⼀般 void* 类型的指针是使用在函数参数的部分,用来接收不同类型数据的地址,这样的设计可以实现泛型编程的效果,使得⼀个函数来处理多种类型的数据

四、const修饰指针

(一)const修饰变量

        const修饰变量的时候,叫:常变量;

        本质还是变量,只是不能被修改;

        变量是可以修改的,如果把变量的地址交给⼀个指针变量,通过指针变量的也可以修改这个变量,若不想变量被直接修改,就使用const修饰变量起限制作用

#include <stdio.h>
int main()
{int m = 0;m = 20;//m是可以修改的const int n = 0;n = 20;//n是不能被修改的return 0;
}

        上述代码中n是不能被修改的,其实n本质是变量(无法在数组长度中使用),只不过被const修饰后,在语法上加了限制,只要我们在代码中对n进行修改,就不符合语法规则,就报错,致使没法直接修改n

        但是可以拿到n的地址,通过指针对它进行修改,但这是在打破语法规则

int main()
{const int n = 0;printf("n = %d\n", n);int*p = &n;*p = 20;printf("n = %d\n", n);return 0;
}

        结果如下:

        这里的初衷是不让变量改变,但是通过指针还是能打破const的限制,接下来就要对这一象限改进,直接对指针变量做const限制

(二)const修饰指针变量

        ⼀般来讲const修饰指针变量,可以放在 * 的左边,也可以放在 * 的右边,意义是不⼀样的

int * p;//没有const修饰
int const * p;//const 放在*的左边做修饰
int * const p;//const 放在*的右边做修饰

        如下代码演示:

        代码一:

int a = 10;
int b = 20;
int const * p = &a;*p = 200;err
p = &b;√

        代码一分析:

        这个const限制的是 *p,即p指向的变量a不能改变;但是并没有限制p,所以可以修改p所指向的变量;
        放在*的左边,限制的是指针指向的内容,也就是不能通过指针变量来修改它所指的内容;但是指针变量本身可以改变的

        代码二:

int a = 10;
int b = 20;
int * const p = &a;*p = 200;√
p = &b;err

        代码二分析:

        放在*的右边,限制的是指针变量本身,也就是指针变量本身不可以改变,但可以通过指针变量来修改它所指的内容

        结论:const修饰指针变量的时候

const如果放在 * 的左边,修饰的是【指针指向的内容 *p】,保证指针指向的内容不能通过指针来改变,但是【指针变量本身 p】的内容可变;
const如果放在*的右边,修饰的是【指针变量本身 p】,保证了指针变量的地址指向不能修改,但是【指针指向的内容*p】,可以通过指针改变

五、指针的运算

        指针的基本运算有三种,分别是:

        • 指针 + 或 -  整数

        • 指针 - 指针

        • 指针的关系运算(指针的比较)

(一)指针 + 或 -  整数

        因为数组在内存中是连续存放的,只要知道第⼀个元素的地址,顺腾摸瓜就能找到后⾯的所有元素

int arr[10] = {1,2,3,4,5,6,7,8,9,10};

#include <stdio.h>
//指针+- 整数
int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};int *p = &arr[0];int sz = sizeof(arr)/sizeof(arr[0]);for(int i = 0; i < sz; i++){printf("%d ", *(p+i));//p+i 这⾥就是指针+整数}return 0;
}

        注意:指针运算是指对 p 进行运算,而不是对*p,若对 *p 运算,就是对变量a运算了

        在数组中,指针能够“顺腾摸瓜”的原因是:

        ①指针类型决定了【指针+1】的步长,和指针解引用之后的权限;

        ②数组在内存中的地址是连续的

        错误演示代码:

int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};char *p = &arr[0];int sz = sizeof(arr)/sizeof(arr[0]);for(int i = 0; i < sz; i++){printf("%d ", *p);p += 4;}return 0;
}

        代码分析:

        每次打印时,都让p += 4,在打印1~10时恰好正确,

        每次访问都只会访问第一个字节,后面三个字节是直接跳过的,所以两位数的时候是正确的,但是数字大一些就会忽略掉第二个字节的数字,就会出错

(二)指针 - 指针

        【指针 - 指针】的运算前提条件两个指针指向的是同一个空间,否则运算无意义;

        指针 - 指针的【绝对值】,是指针和指针之间【元素的个数】

        应用:求字符串长度 ,如下代码演示:

#include <stdio.h>int my_strlen(char *s)
{char *p = s;//设置尾指针while(*p != '\0' )p++;return p-s;
}int main()
{printf("%d\n", my_strlen("abc"));return 0;
}

        拓展:指针 + 指针?

        答:无意义,类似于 【日期 +- 天数(计算日期)】、【日期 - 日期(算的是两个日期之间差多少天)】有意义,而【日期 + 日期】无意义

(三)指针的关系运算(指针的比较)

        应用:做判断条件使用,数组中,若一个地址小于另一个地址,则执行语句

#include <stdio.h>int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};int *p = &arr[0];int sz = sizeof(arr)/sizeof(arr[0]);while(p<arr+sz) //指针的⼤⼩⽐较{printf("%d ", *p);p++;}return 0;
}

六、野指针

        概念: 野指针就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

(一)野指针造成的原因

1、指针未初始化

        指针变量也是局部变量,不初始化就会给随机值;

        如果将未初始化的指针变量的值作为地址来进行解引用操作,就会形成非法访问

#include <stdio.h>int main()
{ int *p;//局部变量指针未初始化,默认为随机值*p = 20;return 0;
}

2、指针越界访问

#include <stdio.h>int main()
{int arr[10] = {0};int *p = &arr[0];int i = 0;for(i=0; i<=11; i++){//当指针指向的范围超出数组arr的范围时,p就是野指针*(p++) = i;}return 0;
}

3、指针指向的空间释放

#include <stdio.h>int* test()
{int n = 100;return &n;
}int main()
{int* p = test();printf("%d\n", *p);return 0;
}

(二)如何规避野指针

1、指针初始化

        如果明确知道指针指向哪里就直接赋值地址,如果不知道指针应该指向哪里,可以给指针赋值NULL,NULL 是C语言中定义的⼀个标识符常量,值是0(这个0在C语言中会被强制转化为void*类型),0也是地址,这个地址是无法使用的,读写该地址会报错

        演示代码如下:

#include <stdio.h>
int main()
{int num = 10;int* p1 = &num;int* p2 = NULL;return 0;
}

2、小心指针越界

        ⼀个程序向内存申请了哪些空间,通过指针也就只能访问哪些空间,不能超出范围访问,超出了就是越界访问

3、指针变量不再使用时,及时置NULL,指针使用之前检查有效性

        当指针变量指向⼀块区域的时候,我们可以通过指针访问该区域,后期不再使用这个指针访问空间的时候,我们可以把该指针置为NULL;因为约定俗成的⼀个规则就是:只要是NULL指针就不去访问,同时使用指针之前可以判断指针是否为NULL

        演示代码如下:

int main()
{int arr[10] = {1,2,3,4,5,6,7,8,9,10};int *p = &arr[0];for(int i = 0; i<10; i++){*(p++) = i;}//此时p已经越界了,可以把p置为NULLp = NULL;//下次使⽤的时候,判断p不为NULL的时候再使⽤//...p = &arr[0];//重新让p获得地址if(p != NULL) //判断{//...}return 0;
}

4、避免返回局部变量的地址

        不要返回局部变量的地址

七、assert断言

        

        assert.h 头文件定义了宏 assert ( ) ,用于在运行时确保程序符合指定条件,如果不符合,就报错终止运行,这个宏常常被称为“断言”

        使用:#include <assert.h>;assert(表达式)

        作用:判断是否符合指定条件,如果不符合就会终止运行;【通常用来判断指针变量的有效性】

        判断:判断为真则程序继续向下走,判断为假则报错

int* p = NULL;
...
assert(p != NULL); 
此处经过一些列的代码后,若 p 不等于NULL则正常运行下去,若还是等于NULL,则程序报错,终止运行

        若想取消assert断言,则在#include <assert.h>上面 #define NDEBUG;

        assert断言只在Debug版本中有效,在Release版本中会被优化掉

        缺点:引入了额外的检查,增加了程序的运行时间

八、指针的使用和传址调用

(一)指针的使用:strlen的模拟实现

        库函数strlen的功能是求字符串⻓度,统计的是字符串中 \0 之前的字符的个数

        函数原型如下:

size_t strlen ( const char * str );

        参数str接收⼀个字符串的起始地址,然后开始统计字符串中 \0 之前的字符个数,最终返回长度;

        如果要模拟实现只要从起始地址开始向后逐个字符的遍历,只要不是 \0 字符,计数器就+1,这样直到 \0 就停止,代码如下:

size_t my_strlen(const char * str)
{int count = 0;assert(str);//为了保险,判断传来的是不是空地址while(*str){count++;str++;}return count;
}int main()
{size_t len = my_strlen("abcdef");printf("%zd\n", len);return 0;
}

        注:代码中的 const(不希望原值被修改)和 assert(保险判断)来加强代码使用时的健壮性(鲁棒性)
 

(二)传值调用和传址调用

        传址调用,可以让函数和主调函数之间建立真正的联系,在函数内部可以修改主调函数中的变量;所以未来函数中只是需要主调函数中的变量值来实现计算,就可以采用传值调用,如果函数内部要修改主调函数中的变量的值,就需要传址调用


        以上内容仅供分析,若有错误,请多多指正

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

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

相关文章

ASRock Creator系列GPU:为AI推理及多GPU系统打造,采用16针电源接口的Radeon RX 7900系列显卡

ASRock 正在筹备推出专为人工智能推理和多GPU系统设计的AMD GPU——Creator系列显卡。这一系列显卡采用双槽位、吹风式设计&#xff0c;并配备16针电源连接器&#xff0c;首发产品包括基于Navi 31架构的AMD Radeon RX 7900XTX和RX 7900 XT型号。这些原属于WS系列的显卡最初在20…

机器学习与现代医疗设备的结合:革新医疗健康的未来

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引言 随着技术的不断进步&#xff0c;机器学习&#xff08;Machine Learning, ML&#xff09;在现代医疗设备中的应用正在改变着…

python基础语法 006 内置函数

1 内置函数 材料参考&#xff1a;内置函数 — Python 3.12.4 文档 Python 解释器内置了很多函数和类型&#xff0c;任何时候都能直接使用 内置函数有无返回值&#xff0c;是python自己定义&#xff0c;不能以偏概全说都有返回值 以下为较为常用的内置函数&#xff0c;欢迎补充…

什么是CTO?如何成为一名优秀的CTO?

一、什么是CTO&#xff1f; 首席技术官&#xff08;CTO&#xff09;是一位负责领导和管理企业技术战略的高级职务。CTO的主要职责包括规划技术战略、监督研发活动、领导技术团队等。 二、CTO的主要职责 首席技术官&#xff0c;即CTO&#xff0c;是企业中负责技术和研发的高级管…

Redies基础篇(一)

Redis 是一个高性能的key-value数据库。Redies支持存储的value类型相对更多&#xff0c;包括string(字符串)、list(链表)、set(集合)和zset(有序集合)。这些数据类型都支持push/pop、add/remove及取交集并集和差集及更丰富的操作&#xff0c;而且这些操作都是原子性的&#xff…

【ETABS】【RHINO】案例:Swallow to ETABS

文章目录 01. Swallow Overview总览1 LOAD&#xff1a;Defination of LoadCase、Response Combo2 SectionArea Section and Area Load&#xff08;面截面定义与指定&#xff0c;面荷载指定&#xff09;Frame Section with rebarattr and linear load&#xff08;带钢筋属性框架…

下载,连接mysql数据库驱动(最详细)

前言 本篇博客&#xff0c;我讲讲如何连接数据库&#xff1f;我使用mysql数据库举例。 目录 下载对应的数据库jar 包 百度网盘 存有8.4.0版本压缩包&#xff1a;链接&#xff1a;https://pan.baidu.com/s/13uZtXRmuewHRbXaaCU0Xsw?pwduipy 提取码&#xff1a;uipy 复制这…

STM32-TIM定时器

本内容基于江协科技STM32视频内容&#xff0c;整理而得。 文章目录 1. TIM1.1 TIM定时器1.2 定时器类型1.3 基本定时器1.4 通用定时器1.4 高级定时器1.5 定时中断基本结构1.6 预分频器时序1.7 计数器时序1.8 计数器无预装时序1.9 计数器有预装时序1.10 RCC时钟树 2. TIM库函数…

前端面试题11(浅谈JavaScript深拷贝与浅拷贝)

在JavaScript中&#xff0c;数据的复制可以分为浅拷贝&#xff08;Shallow Copy&#xff09;和深拷贝&#xff08;Deep Copy&#xff09;。这两种拷贝方式主要区别在于如何处理对象中的嵌套对象。下面我会详细解释这两者的概念、区别&#xff0c;并提供相应的实现代码。 浅拷贝…

【机器学习实战】Datawhale夏令营:Baseline精读笔记2

# AI夏令营 # Datawhale # 夏令营 在原有的Baseline上除了交叉验证&#xff0c;还有一种关键的优化方式&#xff0c;即特征工程。 如何优化特征&#xff0c;关系着我们提高模型预测的精准度。特征工程往往是对问题的领域有深入了解的人员能够做好的部分&#xff0c;因为我们要…

链式二叉树oj题

1.输入k &#xff0c;找第k层节点个数 int TreeKlevel(BTNode*root,int k) {if (root NULL) {return 0;}if (k 1) {return 1;}return TreeKlevel(root->left, k - 1)TreeKlevel(root->right, k - 1); } 在这里我们要确定递归子问题&#xff0c;第一个就是NULL时返回&…

26_嵌入式系统网络接口

以太网接口基本原理 IEEE802标准 局域网标准协议工作在物理层和数据链路层&#xff0c;其将数据链路层又划分为两层&#xff0c;从下到上分别为介质访问控制子层(不同的MAC子层&#xff0c;与具体接入的传输介质相关),逻辑链路控制子层(统一的LLC子层&#xff0c;为上层提供统…

非同步升压转换器,效率95%你信吗?ETA1611输出电流2A, 22V DCDC

前言&#xff1a; 截止24年7月7日某创报价&#xff1a;500&#xff1a; &#xffe5;0.7856 / 个 建议使用前同时了解下方器件。 2毛钱的SOT23-5封装28V、1.5A、1.2MHz DCDC转换器用于LCD偏置电源和白光LED驱动等MT3540升压芯片 描述 ETA1611 SOT23-6封装 丝印GVYW&#xff0…

c进阶篇(三):字符串函数

1.strlen: strlen - C Reference strlen 函数是一个标准库函数&#xff0c;用于计算以 null 结尾的字符串的长度&#xff0c;也就是字符串中实际字符的数量&#xff0c;不包括最后的 null 终止符 \0。它定义在 <string.h> 头文件中。 函数原型:size_t strlen(const ch…

一篇就够了,为你答疑解惑:锂电池一阶模型-在线参数辨识(附代码)

锂电池一阶模型-在线参数辨识 背景在线 VS 离线 参数辨识递推最小二乘法一阶戴维南Z域离散表达式 背景 锂电池一阶戴维南等效模型的基础知识和离线辨识方法&#xff0c;已经在上一期非常详细地讲解了一轮&#xff08;上期文章请戳此处&#xff09;&#xff0c;本期继续讲解一下…

【数据结构】经典链表题目详解集合(反转链表、相交链表、链表的中间节点、回文链表)

文章目录 一、反转链表1、程序详解2、代码 二、相交链表1、程序详解2、代码 三、链表的中间节点1、程序详解2、代码 四、回文链表1、程序详解2、代码 一、反转链表 1、程序详解 题目&#xff1a;给定单链表的头节点 head &#xff0c;请反转链表&#xff0c;并返回反转后的链…

uniapp/Android App上架三星市场需要下载所需要的SDK

只需添加以下一个权限在AndroidManifest.xml <uses-permission android:name"com.samsung.android.providers.context.permission.WRITE_USE_APP_FEATURE_SURVEY"/>uniapp开发的&#xff0c;需要在App权限配置中加入以上的额外权限&#xff1a;

1958.力扣每日一题7/7 Java(100%解)

博客主页&#xff1a;音符犹如代码系列专栏&#xff1a;算法练习关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ 目录 思路 解题方法 时间复杂度 空间复杂度 Code 思路 首先将指定位…

排序 -- 手撕归并排序(递归和非递归写法)

一、基本思想 归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分治法&#xff08;Divide and Conquer&#xff09;的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到完全有序的序列&#xff1b;即先使每个子序列有…

汉诺塔与青蛙跳台阶

1.汉诺塔 根据汉诺塔 - 维基百科 介绍 1.1 背景 最早发明这个问题的人是法国数学家爱德华卢卡斯。 传说越南河内某间寺院有三根银棒&#xff0c;上串 64 个金盘。寺院里的僧侣依照一个古老的预言&#xff0c;以上述规则移动这些盘子&#xff1b;预言说当这些盘子移动完毕&am…