一、数据结构
根据数据结构中数据之间的关系,将数据结构分类为:
线性结构:线性结构就是数据结构中各个结点具有线性关系。
非线性结构:非线性结构就是数据结构中各个结点之间具有多个对应关系。
二、线性结构存储方式的分类
线性结构的实际存储方式,分为两种:
1、顺序表:将元素顺序的存放在一块连续的存储区里面,元素间的顺序关系由它们的存储顺序自然表示。
2、链表:将元素存放在通过链接构造起来的一系列存储块中,存储区域是非连续的。
3、顺序表和链表的优缺点
链表存储方式由于不需要按照顺序存储,在插入、删除元素时比顺序存储要快,但是在查找一个节点时要比顺序存储要慢。
三、单链表
单链表(Singly Linked List)是一种数据结构,由一系列节点组成。每个节点都包含两部分:数据和指向下一个节点的引用(或链接)。单链表中的第一个节点称为头节点,最后一个节点的下一个引用通常指向空值(None)
四、python代码实现单链表
#定义节点类
class Node:
#初始化节点
def __init__(self, item):
self.item = item #存储具体数据
self.next = None #存储下一个节点的地址
#获取节点元素:node.item
#获取下一个节点:node.next
#表示单链表
class SingleLinkedList:
#初始化链表
def __init__(self, node=None):
#默认指向链表中第一个节点,头结点
self.head = node
#判断链表是否为空
def is_empty(self):
return True if self.head == None else False
#链表长度
def length(self):
#定义变量,记录当前节点,初始值为头节点
cur = self.head
#定义计数器,用来记录节点个数
count = 0
#循环判断当前节点是否为空
while cur is not None:
#进入循环里面,说明节点不为空,计数器加一
count += 1
#cur变量指向下一个节点
cur = cur.next
#返回计数器结果
return count
# 链表遍历
def travel(self):
# 定义变量,记录当前节点,初始值为头节点
cur = self.head
# 循环判断当前节点是否为空
while cur is not None:
# 打印cur的item值
print(cur.item)
# cur变量指向下一个节点
cur = cur.next
# 链表头部添加元素
def add(self, item):
# 根据元素值,创建节点
new_node = Node(item)
# 新节点的地址域为头结点
new_node.next = self.head
# 更新头结点指向为新节点
self.head = new_node
# 链表尾部添加新元素,(最后一个节点的next指向为None)
def append(self, item):
# 根据元素值,创建节点
new_node = Node(item)
# 判断链表是否为空,为空时,头结点指向新的节点
if self.is_empty():
self.head = new_node
else:
# 定义变量,记录当前节点,初始值为头节点
cur = self.head
# 当前节点的地址域不为空时,就一直循环获取链表中的节点
while cur.next is not None:
# cur变量指向下一个节点
cur = cur.next
# 走到这里说明当前节点的地址域为None,设置当前节点的地址域为新节点
cur.next = new_node
# 指定位置添加元素
# pos:添加的位置
def insert(self, pos, item):
# 判断要添加的位置,如果小于等于0,就在头部添加
if pos <= 0:
# 调用在头部添加元素
self.add(item)
# 判断要添加的位置,如果打于等于链表长度,就在尾部添加
elif pos > self.length():
# 调用在尾部添加元素
self.append(item)
else:
# 根据元素值,创建节点
new_node = Node(item)
# 定义变量,记录当前节点,初始值为头节点
cur = self.head
# 定义count变量,获取插入位置前的值
count = 0
# 循环判断获取插入位置前的那个元素
while count < pos - 1:
cur = cur.next
count += 1
# 设置新节点的地址域为当前节点的地址域
new_node.next = cur.next
# 设置当前节点的地址域为新节点
cur.next = new_node
##解释为什么要先把新的节点的地址域设置为当前节点的地址域,再将当前节点的地址域设置为新节点的。
#例子说明:间谍A与间谍B,一直是单向联络,他们只知道自己的下家是谁,,间谍A是间谍B的上家,有一天间谍业务太过繁忙,
# 间谍总部派出间谍X去协助A、B,间谍之间有一个联络密码本叫next上面记录了下家的联络方式,但是密码本上面只能写一个
# 下家的联络方式,一旦修改后再也找不到之前的,间谍X想联络间谍B,得先找到他的上家间谍A,间谍A把密码本next给间谍x,
# 因为间谍x的密码本上面的联系方式是间谍A给的,所有间谍x.next = 间谍A.next 因为间谍A把间谍B的联络方式next给了间谍x,
# 以后就由间谍A来联络间谍X,间谍X来联系间谍B,也就是说间谍A的next上面就写了X的联络方式,间谍A.next = 间谍X
# 删除节点
def remove(self, item):
# 定义变量,记录当前节点,初始值为头节点
cur = self.head
# 定义pre变量,表示要被删除的节点的前一个节点
pre = None
# 当cur不为空时,一直循环
while cur is not None:
# 判断当前节点的元素域是否是要删除的节点的元素域
if item == cur.item:
# 判断要删除的节点是否是头节点
if cur == self.head:
# 让头结点指向当前节点的下一个节点
self.head = cur.next
# 如果不是头结点
else:
# 当前节点的前一个节点地址域指向当前节点的地址域(下一个节点)
pre.next = cur.next
break
else:
pre = cur
cur = cur.next
#per: 当前节点的前一个节点
#判断链表是否存在该元素
def sreach(self, item):
# 定义变量,记录当前节点,初始值为头节点
cur = self.head
# 当节点不为空时,一直循环
while cur is not None:
# 判断当前节点的item值和要查找的item值是否一致
if cur.item == item:
return True
# 走这里说明没有匹配上,继续判断下一个节点
cur = cur.next
return False
if __name__ == '__main__':
#创建单个节点
p1 = Node('强子')
print(p1.item)
print(p1.next)
print('-' * 50)
#创建链表
linked_list = SingleLinkedList(p1)
print(linked_list.head)
print('-' * 50)
# 判断链表是否为空
print(linked_list.is_empty())
print('-' * 50)
#打印链表的长度
print(linked_list.length())
print('-' * 50)
#打印链表内容
linked_list.travel()
print('-' * 50)
#链表头部添加元素
linked_list.add('华强')
linked_list.travel()
print('-' * 50)
#链表尾部添加元素
linked_list.append('刘华强')
linked_list.travel()
print('-' * 50)
#在指定位置添加元素
linked_list.insert(1, '刀哥')
linked_list.travel()
print('-' * 50)
#删除元素
linked_list.remove('强子')
linked_list.travel()
运行结果:
五、总结
python中实现模拟单链表还是比较简单的,文章如果有写的不对的或者写的不好的,欢迎大家指正。