Python数据结构与算法 DAY 02 重点知识总结 链表的实现
一 单链表
单链表图例
class Single(object):
def __init__(self,item):
self.item =item
self.next = None
class Method(object):
# 创建初始值 将代表链首个节点的__head 定义并设置为None 即默认该链没有长度 也没有节点
def __init__(self):
self.__head = None
# 判断 : 该链是否为空
def is_empty(self):
if self.__head == None:
return True
return False
# 链的长度判断:
# 这是其中一种判断方法 这种判断方法的优势在于 不会需要判断该链中是否有节点 因为如果本身是空链 是无法进入循环的 并且number的默认值为0
def length(self):
# 创建一个计数器 用于记录链的数量
number = 0
# 创建一个指针 首先指向链的第一个节点
cur = self.__head
# 创建一个循环 将这个循环从第一个节点进行到最后一个节点 (判断是否为最后一个节点的方法为判断 cur.next是否等于None)
while cur != None:
cur = cur.next
number += 1
return number
# 增: 在链的最前端进行插入
def insert_top(self,item):
# 首先创造新的节点(使用Single类创建一个对象) 包含 item 和 next
single = Single(item)
# 将对象的next指向目前第一个节点 因为目前__head的已经指向了第一个节点 所以我们只需要和head指向的内容相同即可
single.next = self.__head
# 将head的指向转向新的节点
self.__head = single
# 增: 在链的末尾增加
def insert_end(self,item):
# 首先先创建一个新的节点(使用Single类创建一个对象) 包含item 和 next
single = Single(item)
# 由于是加在最后的 所以我们需要定义一个指针 并且让指针指向目前的最后一个
cur = self.__head
# 使用循环实现将指针指向最后目前最后一个节点
while cur.next != None:
# 将指针一次一次向后移动 移动到cur.next == None 为止
cur = cur.next
# 目前cur指针已经指向目前链的最后一个节点了 那么就将最后一个节点的next指向新创建的新节点即可(由于新节点的next默认为None 所以不需要重新设置)
cur.next = single
# 增: 输入插入的位置 在指定的位置插入新的节点 类似于列表内的insert的效果
def insert_middle(self,indexs,item):
'''
:param indexs: 输入插入的索引 类型为整型int
:param item: 插入的值 (用于创建新节点的对象)
:return: None
'''
# 首先先创建一个新的节点
single = Single(item)
# 判断是否为空链
if self.is_empty() == False:
# 判断是否为输入的索引为开头
if indexs<=0:
self.insert_top(item)
# 判断是否输入的索引为末尾
elif indexs > (self.length()-1):
self.insert_end(item)
# 如果插入的位置是在中间
else:
# 创建一个指针 初始值为指向链的第一个节点
cur = self.__head
# 创建一个计数器 目的是判断指针是否移动到需要插入的位置的前一个节点
count = 0
# 写入循环 逻辑是只要计数器(反应的是当前指针指向的索引位置)
while count < (indexs-1):
cur = cur.next
count += 1
# 将新的节点指向目前当前位置之后的节点
single.next = cur.next
# 将目前的节点的next指向新创建的节点
cur.next = single
else:
print('本链为空 默认插入的索引为0')
self.insert_top(item)
# 删除 : 删除其中一个元素
def _delete(self,indexs):
'''
:param indexs: 需要删除的元素的索引
:return:
'''
# 判断该链是否为空链
if self.is_empty() == False:
# 创建游标cur
cur = self.__head
# 创建新游标 precur 这个游标的进度会比cur慢一个单位 也就是指向的是cur上一个节点
precur = None
# 判断输入的indexs是否为链的首个
if indexs <= 0:
self.__head = cur.next
cur.next = None
# 判断输入的indexs是否为链的末尾
elif indexs >= (self.length() - 1):
# 这里写判断条件 目的是 经过循环之后 输出的cur指向的是最后一个节点 而pre指向的是倒数第二个节点
while cur.next != None:
precur = cur
cur = cur.next
# 变换指向 将需要删除目标的上一个节点的next 指向 None
precur.next = None
# 若输入的indexs是否为链的中间
else:
# 设置计数器 计数器反应的部分即为cur的索引
count = 0
# 设置循环 设置判断条件 让循环结束后 cur指向需要删除的目标索引节点 precur指向删除目标节点上一个节点
while count < indexs:
precur = cur
cur = cur.next
count += 1
# 变换指向 将需要删除目标的上一个节点的next 指向 需要删除目标后面的节点
precur.next = cur.next
# 将需要删除目标的next设置为None
cur.next = None
else:
print('error,该链为空')
# 查找该节点是否存在
def seaching(self,item):
# 设置指针 并默认指向head
cur = self.__head
# 设置循环 循环判断指向的节点的item值和输入的item值是否相同 相同则输出True 并且停止循环
while cur != None:
if cur.item == item:
return True
else:
cur = cur.next
# 如果遍历结束没有找到 则返回False
else:
return False
# 遍历链
def travel(self):
# 创建指针
cur = self.__head
while cur != None:
print(cur.item,end=' ')
cur = cur.next
else:
print()
if __name__ == "__main__":
ll = Method()
ll.insert_top(1)
ll.insert_top(2)
ll.insert_end(3)
ll.insert_middle(2, 4)
print ("length:",ll.length())
ll.travel()
print( ll.seaching(3))
print (ll.seaching(5))
ll._delete(1)
print ("length:",ll.length())
ll.travel()
二 单向循环链表
单向循环链表图例
代码实现:
class Single(object):
def __init__(self,item):
self.item =item
self.next = None
class Method(object):
def __init__(self):
self.__head = None
def is_empty(self):
if self.__head == None:
return True
else:
return False
def length(self):
if self.is_empty() == True:
return 0
else:
count = 1
cur = self.__head
while cur.next != self.__head:
cur = cur.next
count += 1
return count
def traval(self):
if self.is_empty():
return 'empty'
else:
cur = self.__head
while cur.next != self.__head:
print(cur.item,end = ',')
cur = cur.next
print(cur.item)
def insert_top(self,item):
cur = self.__head
single = Single(item)
if self.is_empty() == True:
self.__head = single
single.next = single
else:
single.next = cur
while cur.next != self.__head:
cur = cur.next
cur.next = single
self.__head = single
def insert_end(self,item):
if self.is_empty():
self.insert_top()
else:
cur = self.__head
single = Single(item)
single.next = self.__head
while cur.next != self.__head:
cur = cur.next
cur.next = single
def insert_middle(self,indexs,item):
if indexs<=0:
self.insert_top(item)
elif indexs>(self.length() - 1):
self.insert_end(item)
else:
cur = self.__head
single = Single(item)
count = 0
while count < (indexs -1):
cur = cur.next
count += 1
single.next = cur.next
cur.next = single
def is_exist(self,item):
if self.is_empty():
return 'error,empty'
else:
cur = self.__head
while cur.next != self.__head:
if item == cur.item:
return True
else:
cur = cur.next
else:
if item == cur.item:
return True
else:return False
def delete_(self,item):
if not self.is_exist(item):
print(f'"{item}" is not in this chain')
return
# 判断该节点是否为空节点
elif self.is_empty():
print('there are nothing in this chain')
return
# 设置开头cur : head_cur
head_cur = self.__head
# 设置末尾cur : end_cur
cur = self.__head
while cur.next != self.__head:
cur = cur.next
end_cur = cur
# 重新设置移动cur
cur = self.__head
# 判断该链中是否只有一个节点
if self.length() == 1:
if item == cur.item:
self.__head = None
return
else:
print(f'"{item}" is not in this chain')
return
else: # elif self.length() > 1:
# 删除首个
if item == head_cur.item:
while cur.next != self.__head:
cur = cur.next
cur.next = head_cur.next
self.__head = head_cur.next
return
# 删除末尾
elif item == end_cur.item:
pre = self.__head
while pre.next != end_cur:
pre = pre.next
pre.next = head_cur
return
# 删除中间
else:
pre = None
while cur.item != item:
pre = cur
cur = cur.next
pre.next = cur.next
return
# 测试
if __name__ == '__main__':
t1 = Method()
# print(t1.is_empty()) # True
# print(t1.length()) # 0
t1.insert_top(1)
t1.insert_top(5)
t1.insert_end(10)
t1.insert_top(6)
# t1.traval() # 6,5,1,10
t1.insert_middle(2,4)
# t1.traval() # 6,5,4,1,10
# print(t1.is_exist(11))
t1.delete_(6)
t1.traval() # 5,4,1,10
t1.delete_(10)
t1.traval() # 5,4,1
t1.delete_(5)
t1.delete_(4)
t1.traval() # 1
t1.delete_(10) # "10" is not in this chain
t1.delete_(1)
t1.traval()
t1.delete_(10)
三 双向链表
双向链表图例
双向链表的代码实现:
class Node:
def __init__(self, elem):
self.elem = elem
self.next = None
self.pre = None
class DoubleLink():
def __init__(self):
self.__head = None
def is_empty(self):
if self.__head is None:
return True
else:
return False
def length(self):
cur = self.__head
count = 0
while cur != None:
cur = cur.next
count += 1
return count
# 循环打印链表的值
def travel(self):
if self.is_empty():
return
cur = self.__head
while cur != None:
print(cur.elem, end=',')
cur = cur.next
print()
# 在头部添加数据
def add(self, item):
node = Node(item)
if not self.is_empty():
node.next = self.__head
self.__head.pre = node
self.__head = node
# 在尾部添加
def append(self, item):
if self.is_empty():
self.add(item)
else:
node = Node(item)
cur = self.__head
while cur.next != None:
cur = cur.next
cur.next = node
node.pre = cur
def insert(self, pos, item):
if pos <= 0:
self.add(item)
elif pos > self.length() - 1:
self.append(item)
else:
node = Node(item)
cur = self.__head
count = 0
while count < pos:
count += 1
cur = cur.next
node.next = cur
node.pre = cur.pre
cur.pre.next = node
cur.pre = node
def remove(self, item):
if self.is_empty():
return None
cur = self.__head
while cur.next != None:
# 找到节点
if cur.elem == item:
# 如果在第一个位置就找到节点
if cur == self.__head:
self.__head = cur.next
cur.next.pre = None
else:
cur.pre.next = cur.next
cur.next.pre = cur.pre
return
else:
cur = cur.next
if cur.elem == item:
# 只有一个节点
if cur.pre == None:
self.__head = None
else:
# 最后一个节点
cur.pre.next = None
def search(self, item):
cur = self.__head
while cur != None:
if cur.elem == item:
return True
cur = cur.next
return False
if __name__ == '__main__':
s = DoubleLink()
print(s.is_empty())
s.add(100)
s.add(10)
s.add(20)
print(s.is_empty())
print(s.length())
s.travel()
s.append(300)
s.travel()
# 20 10 100 300
s.insert(2, 40)
s.travel()
s.insert(0, 110)
s.travel()
s.insert(100,330)
s.travel()
# 110, 20, 10, 40, 100, 300, 330
s.remove(40)
s.travel()
s.remove(110)
s.travel()
s.remove(330)
# 20,10,40,300
s.travel()
print(s.search(10))
print(s.search(120))
四 栈
栈可以使用顺序表实现 也可以使用链表实现 我们这里封装的是使用顺序表来实现
Stack() 创建一个新的空栈
push(item) 添加一个新的元素item到栈顶
pop() 弹出栈顶元素
peek() 返回栈顶元素
is_empty() 判断栈是否为空
size() 返回栈的元素个数
class Stack():
def __init__(self):
self.item = []
def push(self, item):
# 添加一个新的元素item到栈顶
self.item.insert(0, item)
def pop(self):
# 弹出栈顶元素
self.item.pop(0)
def peek(self):
# 返回栈顶元素
return self.item[0]
def is_empty(self):
# 判断栈是否为空
if not self.item:
return True
else:
return False
def size(self):
# 返回栈的元素个数
return len(self.item)
五 队列
同栈一样,队列也可以用顺序表或者链表实现。
Queue() 创建一个空的队列
enqueue(item) 往队列中添加一个item元素
dequeue() 从队列头部删除一个元素
is_empty() 判断一个队列是否为空
size() 返回队列的大小
class Queue(object):
"""队列"""
def __init__(self):
self.items = []
def is_empty(self):
return self.items == []
def enqueue(self, item):
"""进队列"""
self.items.insert(0,item)
def dequeue(self):
"""出队列"""
return self.items.pop()
def size(self):
"""返回大小"""
return len(self.items)
if __name__ == "__main__":
q = Queue()
q.enqueue("hello")
q.enqueue("world")
q.enqueue("haha")
print q.size()
print q.dequeue()
print q.dequeue()
print q.dequeue()
六 双端队列
双端队列(deque,全名double-ended queue),是一种具有队列和栈的性质的数据结构。
双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行。双端队列可以在队列任意一端入队和出队。
Deque() 创建一个空的双端队列
add_front(item) 从队头加入一个item元素
add_rear(item) 从队尾加入一个item元素
remove_front() 从队头删除一个item元素
remove_rear() 从队尾删除一个item元素
is_empty() 判断双端队列是否为空
size() 返回队列的大小
class Deque(object):
"""双端队列"""
def __init__(self):
self.items = []
def is_empty(self):
"""判断队列是否为空"""
return self.items == []
def add_front(self, item):
"""在队头添加元素"""
self.items.insert(0,item)
def add_rear(self, item):
"""在队尾添加元素"""
self.items.append(item)
def remove_front(self):
"""从队头删除元素"""
return self.items.pop(0)
def remove_rear(self):
"""从队尾删除元素"""
return self.items.pop()
def size(self):
"""返回队列大小"""
return len(self.items)
if __name__ == "__main__":
deque = Deque()
deque.add_front(1)
deque.add_front(2)
deque.add_rear(3)
deque.add_rear(4)
print deque.size()
print deque.remove_front()
print deque.remove_front()
print deque.remove_rear()
print deque.remove_rear()