引子:
一、什么是链表?
1、链表是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,有一系列结点(地址)组成,结点可动态的生成。
2、结点包括两个部分:(1)存储数据元素的数据域(内存空间),(2)存储指向下一个结点地址的指针域。
3、相对于线性表顺序结构,操作复杂。
4.链表分为 (1)单链表 (2)双链表 (3)单向循环链表 (4)双向循环链表
1.链表和数组一样,也是一种线性表
二、链表的作用
1、实现数据元素的存储按一定顺序储存,允许在任意位置插入和删除结点。
2、包括单向结点,双向结点,循环接点
三、链表与数组的区别
说到链表那肯定要聊一下数组,为什么会出现链表呢?
(1)数组:使用一块连续的内存空间地址去存放数据,但
例如:
int a[5]={1,2,3,4,5}。突然我想继续加两个数据进去,但是已经定义好的数组不能往后加,只能通过定义新的数组
int b[7]={1,2,3,4,5,6,7}; ***********这样就相当不方便比较浪费内存资源,对数据的增删不好操作。
(2)链表:使用多个不连续的内存空间去存储数据, 可以 节省内存资源(只有需要存储数据时,才去划分新的空间),对数据的增删比较方便。
正式学习重点内容:
栈与递归的爱恨情仇:
感悟:
通俗讲:
就是
从前有座山,山里有个庙,庙里有个小和尚,他在念:
从前有座山,山里有个庙,庙里有个小和尚,他在念:
从前有座山,山里有个庙,庙里有个小和尚,他在念:
从前有座山,山里有个庙,庙里有个小和尚,他在念:
从前有座山,山里有个庙,庙里有个小和尚......
再通俗讲:
就是简单的套娃问题
递归定义:
使用到递归场景:
递归在数学中的表述:
具有递归特性的数据结构:
举例如下:
拓展:
什么是广义表:
广义表(Lists,又称列表)是一种非线性的数据结构,是线性表的一种推广。即广义表中放松对表元素的原子限制,容许它们具有其自身结构(即可以有子表)。它被广泛的应用于人工智能等领域的表处理语言LISP语言中。在LISP语言中,广义表是一种最基本的数据结构,就连LISP 语言的程序也表示为一系列的广义表
前面讲过,数组即可以存储不可再分的数据元素(如数字 5、字符 'a'),也可以继续存储数组(即 n 维数组)。
但需要注意的是,以上两种数据存储形式绝不会出现在同一个数组中。例如,我们可以创建一个整形数组去存储 {1,2,3},我们也可以创建一个二维整形数组去存储 {{1,2,3},{4,5,6}},但数组不适合用来存储类似 {1,{1,2,3}} 这样的数据。
有人可能会说,创建一个二维数组来存储{1,{1,2,3}}。在存储上确实可以实现,但无疑会造成存储空间的浪费。
对于存储 {1,{1,2,3}} 这样的数据,更适合用广义表结构来存储。
广义表,又称列表,也是一种线性存储结构。同数组类似,广义表中既可以存储不可再分的元素,也可以存储广义表,记作:
LS = (a1,a2,…,an)
其中,LS 代表广义表的名称,an 表示广义表存储的数据。广义表中每个 ai 既可以代表单个元素,也可以代表另一个广义表。
用分治法求解递归问
题:
一般形式(相当于套用模版):
求解n!的阶乘的六种方法
引子:
啥是阶乘?
自然数n!(n的阶乘)是指从1、2……(n-1)、n这n个数的连乘积,即
n!=n×(n-1)×……2×1
如:
1! = 1 =1
2!= 2 * 1 = 2
3!= 3 * 2 * 1 = 6
4! = 4 * 3 * 2 * 1 = 24
5!= 5 * 4 * 3 * 2 * 1 = 120
...
接下来,我们用四种学过的方法实现阶乘:
1、普通的for循环遍历:
#函数实现
def fact(num):
a=1
#for循环遍历
for i in range(1,num+1):
a*=i
return a
n = int(input())
print(fact(n))
运行结果:
5
120
2、while循环
#输入n的值
n=int(input())
product=n
i=1
if n ==0:
print(1)
else:
#while循环
while i <n:
ans=ans*i
i=i+1
print(product)
# product英文有乘积的意思
# 结果:
6
720
3、递归写法一
#函数实现
def fact(n):
if n==0:
return 1
else:
#递归调用
return fact(n-1)*n
n = int(input())
print(fact(n))
# 结果
5
120
写法二:
#函数实现
def factorial(n):
#三元运算表达式
return 1 if n < 2 else n * factorial(n - 1)
#输入n的值
n = int(input())
print(factorial(n))
# 输出
5
120
思维图纸:
练习:
汉诺塔问题:
接下来介绍的就是印度阿三哥著名的汉诺塔问题啦:
Python代码实现:
# 这里使用的花括号是英文版的,就是可以运行没问题
"""汉诺塔问题"""
m = 0
def move(A, n, C):
global m
m += 1
print("第{0}步,将编号为{1}的圆盘,从第{2}个柱子移动到第{3}个柱子上".format(m, n, A, C))
# 中文版的{}和{}英文版的,看着一样 ,但是运行就是不一样
# 真心建议:以后每次打代码是一定要看看自己用的输入法是不是英文
def hanoi(n, A, B, C):
if n == 1:
move(A, 1, C)
else:
hanoi(n - 1, A, C, B)
move(A, n, C)
hanoi(n - 1, B, A, C)
if __name__ == "__main__":
n = int(input("请设置第一个柱子上的盘子数量:"))
a, b, c = '1', '2', '3'
print('第一根柱子上的圆盘数量为:', n)
print('将第一根柱子上的圆盘全部移到第三根柱子上的过程为:')
hanoi(n, a, b, c)
print(m)
"""汉诺塔问题"""
m = 0
#这是中文版的花括号代码
# 就是运行时结果有问题
def move(A, n, C):
global m
m += 1
print("第{0}步,将编号为{1}的圆盘,从第{2}个柱子移动到第{3}个柱子上".format(m, n, A, C))
# 中文版的{}和{}英文版的,看着一样 ,但是运行就是不一样
def hanoi(n, A, B, C):
if n == 1:
move(A, 1, C)
else:
hanoi(n - 1, A, C, B)
move(A, n, C)
hanoi(n - 1, B, A, C)
if __name__ == "__main__":
n = int(input("请设置第一个柱子上的盘子数量:"))
a, b, c = '1', '2', '3'
print('第一根柱子上的圆盘数量为:', n)
print('将第一根柱子上的圆盘全部移到第三根柱子上的过程为:')
hanoi(n, a, b, c)
print(m)
规则:
递归算法的效率分析:
效率计算原理图:
从上述我们不难发现:
递归求解的优缺点: