华子目录
- 线性表的定义
- 前驱与后继
- 1.顺序表(顺序存储结构)
- `python列表与数组的区别`
- 列表
- 数组
- 1.1插入数据
- 实例
- 1.2删除元素
- 实例
- 1.3查找元素
- 1.4修改元素
- 1.5综合示例
- 2.单链表
- 2.1单链表的初始化
- 2.2插入元素
- 示例
- 注意
- 2.3删除元素
- 示例
- 2.4修改元素
- 2.5查找元素
- 2.6综合示例
线性表的定义
线性表
:零个
或多个数据元素
的有限序列- 在逻辑结构上具有
线性关系
。将具有“一对一
”关系的数据“线性”地存储到物理空间
中,这种存储结构
就称为线性存储结构
(简称线性表
)。 线性表
元素的个数n
(n>=0
)定义为线性表
的长度,当n=0
时,称为空表
。- 在较
复杂
的线性表
中,一个数据元素
可以有若干个数据项
组成。 线性表
又可以分为顺序表
(顺序存储结构
)和链表
(链式存储结构
)
前驱与后继
- 某一元素的
左侧相邻元素
称为“直接前驱
”,位于此元素左侧
的所有元素
都统称为“前驱元素
” - 某一元素的
右侧相邻元素
称为“直接后继
”,位于此元素右侧
的所有元素
都统称为“后继元素
”
1.顺序表(顺序存储结构)
- 用一段
地址连续
的存储单元
依次存储线性表
的数据元素
。
python列表与数组的区别
列表
列表
是顺序表
,不是链式表
列表
(其他语言称为数组)是一种基本数据类型
- 当进行
列表
取值a[2]
时,列表
中的每一个格子
存的是值的地址
。当进行a[2]
时,它取得是a[2]
的地址。通过地址
指向来取值
。 python
不需要提前申请列表长度
,因为python
内部会自动申请内存。
python
列表插入
和删除
的时间复杂度
都是O(n)
数组
- 当进行
数组
取值时a[2]
,假如说电脑是32
位,a
开头编号是100
,内存
内部会执行100+2*4=108
,取到a[2]
对应的值
。 数组元素
类型要相同
数组长度固定
1.1插入数据
向已有顺序表中插入数据元素,根据插入位置
的不同,可分为以下3
种情况:
在表头插入元素
在表的中间位置插入元素
在表尾插入元素
虽然数据元素插入
顺序表中的位置
有所不同,但是都使用的是同一种方式
去解决,即:通过遍历
,找到数据元素
要插入
的位置
,然后做如下两步
工作:
- 将要
插入
位置元素
以及后续的元素
整体向后移动一个位置
- 将
插入的元素
放到腾出来的位置上
实例
在 {1,2,3,4,5}
的第 3
个位置上插入元素 6
,实现过程如下:
- 遍历至
顺序表
存储第3
个数据元素的位置
- 将元素
3
以及后续元素 4 和 5 整体
向后
移动一个位置
- 将
新元素 6
放入腾出的位置
1.2删除元素
从顺序表
中删除指定元素
,实现起来非常简单,只需找到目标元素
,并将其后续所有元素
整体前移 1
个位置即可。
后续元素
整体前移一个位置
,会直接将目标元素删除
,可间接实现删除元素的目的
实例
从 {1,2,3,4,5}
中删除元素 3
的过程如图所示:
- 找到目标元素
- 后续元素整体前移
1.3查找元素
顺序表中查找目标元素
,可以使用多种查找算法
实现,比如说二分查找算法、插值查找算法
等。
1.4修改元素
顺序表修改元素
的实现过程
是:
找到目标元素
直接修改该元素的值
1.5综合示例
import random
class SqList:
# 初始化顺序表
def __init__(self, length):
self.length = length #表示顺序表的长度(元素个数)
self.sqlist = [random.randint(1, 100) for i in range(length)] #顺序表内容
# 返回所有元素
def ShowList(self):
return self.sqlist
# 遍历所有元素
def ErgodList(self):
for i in range(self.length):
print(f"第{i+1}个元素值为{self.sqlist[i]}")
# 取值(按位取值)
def GetElement(self, i):
# 首先判断插入的位置是否在合法范围内[0,length-1]
if i < 1 or i > self.length:
return False
return self.sqlist[i - 1]
# 查找
def FindElement(self, e):
for i in range(self.length):
if e == self.sqlist[i]:
print(f"查找的元素在第{i+1}个位置")
break
else:
print("无查找元素")
# 插入
def InsertList(self, i, e):
if i < 1 or i > self.length+1:
return False
self.sqlist.insert(i - 1, e)
self.length += 1
return True
# 删除(按位删除)
def DeleteList_space(self, i):
if i < 1 or i > self.length:
return False
self.sqlist.pop(i - 1)
self.length -= 1
return True
# 删除(按值删除)
def DeleteList_value(self, e):
for i in range(self.length):
if e == self.sqlist[i]:
self.sqlist.pop(i)
self.length -= 1
return True
return False
# 修改(按值修改)
def SetElement(self, eold, enew):
for i in range(self.length):
if eold == self.sqlist[i]:
self.sqlist[i] = enew
return True
return False
# 修改(按位修改)
def SetElement_space(self, i, enew):
if i < 1 or i > self.length:
return False
self.sqlist[i-1] = enew
return True
l = eval(input("请输入初始化长度:"))
my_sqlist = SqList(l) #初始化对象
# 输出所有值
mylist = my_sqlist.ShowList()
print(mylist)
print("------------------------------------------------")
# 遍历元素
my_sqlist.ErgodList()
print("------------------------------------------------")
# 插入元素
i, e = map(int, input("请输入插入元素的位置和值(空格分割):").split())
my_sqlist.InsertList(i, e)
print(f"插入后列表:{my_sqlist.sqlist}")
print("------------------------------------------------")
# 删除(按值删除)
e = eval(input("请输入要删除的值:"))
my_sqlist.DeleteList_value(e)
print(f"删除之后的列表{my_sqlist.sqlist}")
print("------------------------------------------------")
# 删除(按位删除)
i = eval(input("请输入删除元素的位置:"))
my_sqlist.DeleteList_space(i)
print(f"删除之后的列表{my_sqlist.sqlist}")
print("------------------------------------------------")
# 修改 (按值修改)
old, new = map(int, input("请输入需要修改的值和新值:").split())
my_sqlist.SetElement(old, new)
print(f"修改之后的列表{my_sqlist.sqlist}")
print("------------------------------------------------")
# 修改(按位修改)
i, new = map(int, input("请输入需要修改的位置和新值:").split())
my_sqlist.SetElement_space(i, new)
print(f"修改之后的列表{my_sqlist.sqlist}")
print("------------------------------------------------")
# 查找
e = eval(input("请输入要查找的值:"))
my_sqlist.FindElement(e)
请输入初始化长度:5
[98, 27, 99, 63, 54]
------------------------------------------------
第1个元素值为98
第2个元素值为27
第3个元素值为99
第4个元素值为63
第5个元素值为54
------------------------------------------------
请输入插入元素的位置和值(空格分割):6 99
插入后列表:[98, 27, 99, 63, 54, 99]
------------------------------------------------
请输入要删除的值:99
删除之后的列表[98, 27, 63, 54, 99]
------------------------------------------------
请输入删除元素的位置:2
删除之后的列表[98, 63, 54, 99]
------------------------------------------------
请输入需要修改的值和新值:98 0
修改之后的列表[0, 63, 54, 99]
------------------------------------------------
请输入需要修改的位置和新值:2 66
修改之后的列表[0, 66, 54, 99]
------------------------------------------------
请输入要查找的值:0
查找的元素在第1个位置
进程已结束,退出代码0
2.单链表
- 为了表示每个数据元素 ai 与其
直接后继数据
元素 ai+1 之间的逻辑关系
,对数据元素 ai 来说,除了存储其本身的信息之外,还需存储一个指示其直接后继
的信息(即直接后继的存储位置
)。我们把存储数据元素信息
的域
称为数据域
,把存储直接后继位置
的域
称为指针域
。指针域
中存储的信息称做指针
。这两部分信息组成数据元素 ai 的存储映像
,称为结点(Node)
。 n个结点
链结成一个链表
,即为线性表
(a1,a2,…,an
)的链式存储结构
,因为此链表
的每个结点
中只包含一个指针域
,所以叫做单链表
。
头指针
:一个普通的指针,它的特点是永远指向链表第一个节点
的位置头节点
:其实就是一个不存任何数据
的空节点
,通常作为链表
的第一个节点
。对于链表来说,头节点不是必须的首元节点
:由于头节点(也就是空节点)的缘故,链表中称第一个存有数据的节点
为首元节点
其他节点
:链表中其他的节点
- 注意:
链表
中有头节点
时,头指针
指向头节点
;反之,若链表
中没有头节点
,则头指针
指向首元节点
。
2.1单链表的初始化
- 声明一个
头指针
(如果有必要,可以声明一个头节点
) - 创建多个
存储数据
的节点
,在创建的过程中,要随时与其前驱节点
建立逻辑
关系
2.2插入元素
同顺序表一样,向链表中增添元素,根据添加位置不同,可分为以下 3 种情况:
头插法
:插入到链表的头部
(头节点
之后),作为首元节点
中插法
:插入
到链表中间
的某个位置
尾插法
:插入
到链表
的最末端
,作为链表
中最后一个数据元素
虽然新元素
的插入位置
不固定,但是链表
插入元素的思想是固定的
,只需做以下3步
操作,即可将新元素
插入到指定的位置
:
- 找到
插入位置
的前一个结点
- 将
新结点
的next指针
指向插入
位置后
的结点
- 将
插入位置前结点
的next指针
指向插入结点
示例
例如,我们在链表 {1,2,3,4}
的基础上分别实现在头部
、中间部位
、尾部
插入新元素 5
,其实现过程如图1
所示:
- 从图中可以看出,虽然
新元素
的插入位置
不同,但实现插入操作
的方法
是一致的
,都是先执行步骤 1
,再执行步骤 2
注意
链表插入元素
的操作必须是先步骤 1
,再步骤 2
;反之,若先执行骤步 2
,除非再添加一个指针
,作为插入位置
后续链表的头指针
,否则会导致插入位置后的这部分链表丢失
,无法再实现步骤1
2.3删除元素
从链表
中删除指定数据元素
时,实则就是将存有该数据元素
的节点
从链表
中摘除
,但作为一名合格的程序员
,要对存储空间负责
,对不再利用
的存储空间
要及时释放
。因此,从链表
中删除数据元素
需要进行以下 2
步操作:
- 将
结点
从链表
中摘下来
手动释放掉结点
,回收被结点占用的存储空间
其中,从链表
上摘除某节点
的实现非常简单,只需找到该节点
的直接前驱节点temp
temp.next = temp.next.next
示例
例如,从存有 {1,2,3,4}
的链表
中删除元素3
,则此代码
的执行效果
如图 2
所示:
2.4修改元素
修改
链表中的元素
,只需通过遍历
找到存储此元素的节点
,对节点
中的数据域
做更改操作即可
2.5查找元素
- 在
链表
中查找
指定数据元素
,最常用
的方法
是:从表头
依次遍历
表中节点
,用被查找元素
与各节点数据域
中存储
的数据元素
进行比对
,直至比对成功
或遍历
至链表最末端
的NULL
(比对失败的标志
) 注意
,遍历有头节点
的链表
时,需避免
头节点对测试数据
的影响
2.6综合示例
# 定义节点类,包含两个成员:节点数据域和指向下一个节点的指针域(带有头节点的单链表)
class SingleNode:
def __init__(self, item):
self.item = item #数据域
self.next = None #指针域
class SingleLinkList:
def __init__(self):
self.head = None
# 判断链表是否为空
def is_empty(self):
return self.head == None
# 输出链表长度
def get_length(self):
return len(self.travel())
# 遍历整个链表
def travel(self):
# 思路就是先判断链表是否为空
# 为空直接返回None
# 不为空的话,就先定义一个列表,然后通过next指针从头指针开始遍历,依次将节点存储的值加入列表中,直到下一个指针指向为空,则停止遍历
if self.is_empty():
return None
else:
curlist = []
cur = self.head
while cur != None:
curlist.append(cur.item)
cur = cur.next
return curlist
# 头插法创建单链表
def add(self,newItem):
node = SingleNode(newItem)
node.next = self.head
self.head = node
# 尾插法
def append(self,newItem):
node = SingleNode(newItem)
if self.is_empty():
return self.add(newItem)
# 从头节点开始遍历
nod = self.head
while nod.next != None:
nod = nod.next
nod.next = node
# 指定位置添加元素
def insert(self, pos, newItem): # 在指定pos位置上添加newItem元素
# 链表的插入需要分几种情况
# 第一步:判断pos是否在合理范围内,如果不在,则直接终止
# 第二步:判断pos是否在第一个,如果是则采用头插法
# 第三步:如果pos在最后一个,则采用尾插法
# 第四步:如果即不在头,也不在尾,则通过循环遍历到pos位置,再用insert插入
node = SingleNode(newItem)
cur = self.head
count = 0
if pos == 0:
return self.add(newItem)
elif pos < (self.get_length()):
while count < pos - 1: #找到指定位置的前一个节点
cur = cur.next
count += 1
node.next = cur.next
cur.next = node
elif pos == (self.get_length()):
return self.append(newItem)
else:
return '输入的位置有误,请确认'
# 删除指定位置上的节点
def remove(self, pos):
# 第一步:判断给定的pos是否在合理范围内
# 第二步:通过循环,遍历到pos位置,遍历期间通过next指针依次指向下一个节点
# 第三步:找到指定位置的节点后,通过nod.next = nod.next.next删除
cur = self.head
count = 0
if 1 <= pos < (self.get_length()):
while count < pos - 1: #找到指定位置的前一个节点
cur = cur.next
count += 1
cur.next = cur.next.next
elif pos == 0:
self.head = cur.next
else:
return '输入的位置有误,请确认'
# 查找指定位置的节点值
def find(self, pos):
cur = self.head
count = 0
if 0 <= pos < (self.get_length()):
while count < pos: #找到指定位置的节点
cur = cur.next
count += 1
return cur.item
else:
return '输入的位置有误,请确认'
# 更新链表中某个位置的值
def update(self, pos, newItem):
cur = self.head
count = 0
if 0 <= pos < (self.get_length()):
while count < pos: #找到指定位置的节点
cur = cur.next
count += 1
cur.item = newItem
else:
return '输入的位置有误,请确认'
# 清空链表
def clear(self):
self.head = None
singlelinklist = SingleLinkList() #实例化对象
print("初始化单链表:",singlelinklist)
print("-----------------------------")
print("判断单链表是否为空:",singlelinklist.is_empty())
print("-----------------------------")
# 添加数据
import random
for i in range(10):
singlelinklist.add(random.randint(1,100))
# 遍历数据
print("遍历单链表:",singlelinklist.travel())
print("-----------------------------")
print("判断单链表是否为空:",singlelinklist.is_empty())
print("-----------------------------")
# 末尾添加数据
singlelinklist.append(10)
print("末尾添加元素后的单链表遍历结果:",singlelinklist.travel())
print("-----------------------------")
# 开头添加数据
singlelinklist.add(1)
print("开头添加元素后的单链表遍历结果:",singlelinklist.travel())
print("-----------------------------")
# 查看数据长度
print("单链表长度:",singlelinklist.get_length())
print("-----------------------------")
# 指定位置插入数据,位置从0开始
singlelinklist.insert(1, 13)
print("插入数据后的遍历单链表:",singlelinklist.travel())
print("-----------------------------")
# 删除指定位置数据
singlelinklist.remove(0)
print("删除数据后的遍历单链表:",singlelinklist.travel())
print("-----------------------------")
# 更新指定位置数据
singlelinklist.update(2, 2)
print("更新数据后的遍历单链表:",singlelinklist.travel())
print("-----------------------------")
# 清空所有数据
singlelinklist.clear()
print("清空数据后的遍历单链表:",singlelinklist.travel())
初始化单链表: <__main__.SingleLinkList object at 0x0000020DA4358460>
-----------------------------
判断单链表是否为空: True
-----------------------------
遍历单链表: [39, 42, 88, 51, 64, 60, 66, 29, 29, 35]
-----------------------------
判断单链表是否为空: False
-----------------------------
末尾添加元素后的单链表遍历结果: [39, 42, 88, 51, 64, 60, 66, 29, 29, 35, 10]
-----------------------------
开头添加元素后的单链表遍历结果: [1, 39, 42, 88, 51, 64, 60, 66, 29, 29, 35, 10]
-----------------------------
单链表长度: 12
-----------------------------
插入数据后的遍历单链表: [1, 13, 39, 42, 88, 51, 64, 60, 66, 29, 29, 35, 10]
-----------------------------
删除数据后的遍历单链表: [13, 39, 42, 88, 51, 64, 60, 66, 29, 29, 35, 10]
-----------------------------
更新数据后的遍历单链表: [13, 39, 2, 88, 51, 64, 60, 66, 29, 29, 35, 10]
-----------------------------
清空数据后的遍历单链表: None