python从入门到坚持
一.链表
1.什么是链表?
链表(Linked List):是一种常见的基础数据结构,是一只种类线性表,但是不像顺序表一样连续存储数据,而是在每一个节点(数据存储单元)里存放下一个节点的位置信息(即地址)。
顺序表的构建需要预先知道数据大小来申请连续的存储空间,而在进行空充时又需要进行数据的搬迁,所以使用起来并不是很灵活。链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。
2.顺序表与链表
二.单链表
1.单链表
单向链表也叫单链表,每个节点包含两个域,一个信息域(元素域)和一个链接域。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。
- 表元素域elem用来存放具体的数据。
- 链接域next用来存放下一个节点的位置(python中的标识)
- 变量p指向链表的头节点(首节点)的位置,从p出发能找到表中的任意节点。
2.单链表的操作
class Node(object):
"""单链表的节点封装"""
def __init__(self, element):
"""element存放数据元素"""
self.element = element
self.next = None
def __str__(self):
return self.element
class SingleLink(object):
def __init__(self):
#初始化,链表为空
self.head = None
def is_empty(self):
#判断链表是否为空
return self.head == None
def __len__(self):
"""
链表长度:
1.如果当前链表为空, 直接返回0;
2.如果当前链表不为空, 依次遍历链表的每一个元素,计算长度
:return:
"""
if self.is_empty():
return 0
else:
cur = self.head
lenLink = 0
while cur != None:
lenLink += 1
cur = cur.next
return lenLink
def travel(self):
"""遍历链表"""
if not self.is_empty():
cur = self.head
while cur.next != None:
print(cur.element, end=',')
cur = cur.next
print(cur.element)
else:
print('空链表')
def add(self, item):
"""
头部添加元素
1. 先创建一个保存item值的节点
2. 将新节点的链接域next指向头节点,即head指向的位置
3. 将链表的头head指向新节点
"""
node = Node(item)
node.next = self.head
self.head = node
def append(self, item):
"""
尾部添加元素
1. 先判断链表是否为空,若是空链表,则将head指向新节点
2. 若不为空,则找到尾部,将尾节点的next指向新节点
"""
node = Node(item)
if self.is_empty():
self.head = node
else:
cur = self.head
while cur.next != None:
cur = cur.next
cur.next = node
def insert(self, index, item):
"""
指定位置添加元素
1. 若指定位置index为第一个元素之前,则执行头部插入
2. 若指定位置超过链表尾部,则执行尾部插入
3. 否则, 找到指定位置
"""
if index <= 0:
self.add(item)
elif index >= len(self):
self.append(item)
else:
node = Node(item)
count = 0 # 当前位置
cur = self.head
while count < index - 1:
count += 1
cur = cur.next
node.next = cur.next
cur.next = node
def remove(self, item):
"""
删除指定元素的节点:
1 2 3 4 5
1. 如果删除的是头结点, 指针直接指向头结点的下一个节点;
2. 如果删除的不是头结点, 一直循环, 知道找到要删除的节点元素;
"""
pre = None
cur = self.head
if cur.element == item:
self.head = self.head.next
else:
while cur:
if cur.element != item:
pre = cur
cur = cur.next
else:
pre.next = pre.next.next
break
def search(self, item):
cur = self.head
while cur:
if cur.element == item:
return True
cur = cur.next
else:
return False
if __name__ == '__main__':
# 实例化单链表对象
link = SingleLink()
# 长度获取
print("链表长度: ", len(link))
# 遍历链表
link.travel()
print("链表是否为空? ", link.is_empty())
print("添加元素:")
link.append(1)
link.append(2)
link.add(3)
link.insert(1,'hello')
# 3 'hello' 1 2
# 长度获取
print("链表长度: ", len(link))
# 遍历链表
link.travel()
print("链表是否为空? ", link.is_empty())
print("删除元素")
link.remove(1)
link.travel()
link.search(2)
link.travel()```
三.单向循环链表
1.单向循环链表
单链表的一个变形是单向循环链表,链表中最后一个节点的next域不再为None,而是指向链表的头节点。
2.单向循环链表的操作
class Node(object):
def __init__(self, item):
self.item = item
self.next = None
class SingleCycLink(object):
def __init__(self):
self.head = None
def is_empty(self):
return self.head == None
def __len__(self):
if self.is_empty():
return 0
cur = self.head
count = 1
while cur.next != self.head:
count += 1
cur = cur.next
return count
def trvel(self):
if not self.is_empty():
cur = self.head
while cur.next != self.head:
print(cur.item, end=',')
cur = cur.next
print(cur.item)
else:
print('链表为空')
def add(self, item):
# 在头部添加
node = Node(item)
if self.is_empty():
self.head = node
node.next = self.head
else:
cur = self.head
while cur.next != self.head:
cur = cur.next
cur.next = node
node.next = self.head
self.head = node
def append(self, item):
# 在尾部添加
node = Node(item)
if self.is_empty():
self.head = node
node.next = self.head
else:
cur = self.head
while cur.next != self.head:
cur = cur.next
cur.next = node
node.next = self.head
def insert(self, index, item):
if index <= 0:
self.add(item)
elif index >= len(self):
self.append(item)
else:
node = Node(item)
count = 0
cur = self.head
while count < index - 1:
count += 1
cur = cur.next
node.next = cur.next
cur.next = node
def remove(self, item):
if self.head == None:
print('空链表')
else:
cur = self.head
pre = self.head
if cur.item == item:
while cur.next != self.head:
cur = cur.next
cur.next = pre.next
self.head = pre.next
else:
while cur.next.item != item:
cur = cur.next
cur.next = cur.next.next
def search(self, item):
cur = self.head
while cur.next is not None:
if cur.item == item:
return True
else:
cur = cur.next
else:
return False
link = SingleCycLink()
print('链表长度:', len(link))
link.trvel()
print(link.is_empty())
link.append(3)
link.add(2)
link.insert(1, 'hello')
link.append(6)
link.append(5)
print('链表长度:', len(link))
link.trvel()
link.add(5)
link.remove(4)
link.trvel()
四.双向链表
1.双向链表
**双向链表:**每个节点有两个链接:一个指向前一个节点,当此节点为第一个节点时,指向空值;而另一个指向下一个节点,当此节点为最后一个节点时,指向空值。
2.双向链表的代码操作
"""
双向链表的封装
"""
class Node(object):
"""
双向链表节点的封装
"""
def __init__(self, element):
self.element = element # 数据域
# 指针域
self.next = None # 指向后继节点的指针
self.prev = None # 指向前驱节点的指针
def __str__(self):
return self.element
class DuLinkList(object):
"""
双向链表的封装
"""
def __init__(self):
self.head = None
def is_empty(self):
"""判断双向链表是否为空"""
return self.head == None
def __len__(self):
"""获取双向链表的长度"""
if self.is_empty():
return 0
cur = self.head
linkLen = 0
while cur:
cur = cur.next
linkLen += 1
return linkLen
def travel(self):
"""遍历链表元素"""
if not self.is_empty():
cur = self.head
while cur.next != None:
print(cur.element, end=',')
cur = cur.next
print(cur.element)
else:
print("空链表")
def add(self, item):
"""
头部添加元素
1. 先创建一个保存item值的节点
2. 将新节点的链接域next指向头节点,即head指向的位置
3. 将链表的头head指向新节点
"""
node = Node(item)
if self.is_empty():
self.head = node
else:
node.next = self.head
self.head.prev = node
self.head = node
def append(self, item):
"""
尾部添加元素
1. 先判断链表是否为空,若是空链表,则将head指向新节点
2. 若不为空,则找到尾部,将尾节点的next指向新节点
"""
node = Node(item)
if self.is_empty():
self.head = node
else:
cur = self.head
while cur.next != None:
cur = cur.next
cur.next = node
node.prev = cur
def insert(self, index, item):
"""
指定位置添加元素
1. 若指定位置index为第一个元素之前,则执行头部插入
2. 若指定位置超过链表尾部,则执行尾部插入
3. 否则, 找到指定位置
"""
if index <= 0:
self.add(item)
elif index >= len(self):
self.append(item)
else:
node = Node(item)
count = 0 # 当前位置
cur = self.head
while count < index - 1:
count += 1
cur = cur.next
node.next = cur.next
cur.next = node
node.prev = cur
cur.next.prev = node
def remove(self, item):
"""
删除指定元素的节点:
1 2 3 4 5
1. 如果删除的是头结点, 指针直接指向头结点的下一个节点;
2. 如果删除的不是头结点, 一直循环, 知道找到要删除的节点元素;
"""
if self.is_empty():
return
pre = None
cur = self.head
# 如果删除的是头结点, 指针直接指向头结点的下一个节点;
if cur.element == item:
self.head = self.head.next
else:
while cur:
if cur.element != item:
pre = cur
cur = cur.next
else:
# 判断删除的是否为尾部节点, 如果是, 则直接让pre.next指向为None;
if not cur.next:
pre.next = None
break
else:
# pre.next = pre.next.next
pre.next = cur.next
cur.next.prev = pre
break
def search(self, item):
cur = self.head
while cur:
if cur.element == item:
return True
cur = cur.next
else:
return False
if __name__ == '__main__':
# 实例化双向链表对象
link = DuLinkList()
# 长度获取
print("链表长度: ", len(link))
# 遍历链表
link.travel()
print("链表是否为空? ", link.is_empty())
# print("添加头结点:")
# for item in range(5):
# link.add(item) # 4 3 2 1 0
#
# # 长度获取
# print("链表长度: ", len(link))
# # 遍历链表
# link.travel()
# print("链表是否为空? ", link.is_empty())
print("追加结点:")
for item in range(5):
link.append(item) # 0 python 1 2 3 4
# 长度获取
print("链表长度: ", len(link))
# 遍历链表
link.travel()
print("链表是否为空? ", link.is_empty())
print("指定位置插入元素")
link.insert(1, 'python')
# 长度获取
print("链表长度: ", len(link))
# 遍历链表
link.travel()
print("链表是否为空? ", link.is_empty())
print("删除元素") # 0 python 1 2 3 4
link.remove(4)
link.travel()
print("查找元素:")
print(link.search(1))
print(link.search(10))
五.链表实例
1.删除链表的倒数第N个节点
"""
删除链表的倒数第k个元素
1. 判断用户输入的合法性? link, n
2. 如果输入数据合法
1). p, q
2). 让p指针和q指针之间的间距为k;
3). 让p指针和q指针一块向后移动, 直到q.next为空的时候停止移动;
4). p指针指向哪里? 指向要删除的元素的前一个节点 p.next = p.next.next
"""
from SingleLink import *
def deleteLinkElement(link, n):
#1. 判断用户输入的合法性?
if not link:
return
if not link.head:
return
if n <= 0:
return
# 2.如果输入数据合法
# 1).p, q
p = link.head
q = link.head
# 2).让p指针和q指针之间的间距为k
for item in range(n):
q = q.next
# 3).让p指针和q指针一块向后移动, 直到q.next为空的时候停止移动;
while q.next:
p = p.next
q = q.next
# 4).p指针指向哪里? 指向要删除的元素的前一个节点p.next = p.next.next
p.next = p.next.next
return link
if __name__ == '__main__':
link = SingleLink()
for num in range(5):
link.append(num+1)
link.trvel()
deleteLinkElement(link, 2)
link.trvel()
2.旋转链表
from SingleLink import *
def rorateRight(link, k):
"""
向右移动k个元素(绕圈法):
1. 判断录入数据的合法性? link是否存在? link是否为空? k是否为非负数.
2. 如果数据合法;
1). 访问到链表的最后
2). 首尾相连
3). 对k值进行处理: k = k%len(link)
4). 让指针移动到(len-k-1), 更新链表头结点
5). 断开链表循环的部分
:param link: 单链表对象
:param k: 向右移动的数值
:return:
"""
# 1. 判断录入数据的合法性? link是否存在? link是否为空? k是否为非负数.
if not link:
return
if not link.head:
return
if k < 0:
return
# 2. 如果数据合法;
# 1).访问到链表的最后
cur = link.head
count = 1 # 链表的长度
while cur.next:
cur = cur.next
count += 1
# 2). 首尾相连
cur.next = link.head
# 3). 对k值进行处理: k = k%len(link)
k = k % count
# 4).让指针移动到(len - k - 1),
pre = link.head # 最终指向要断开节点的前一个节点
for i in range(count - k - 1):
pre = pre.next
# 更新链表头结点
link.head = pre.next
# 5).断开链表循环的部分
pre.next = None
return link
if __name__ == '__main__':
link = SingleLink()
for item in range(5): # 1 2 3 4 5
link.append(item + 1)
link.trvel()
print("测试".center(30, '*'))
link1 = rorateRight(link, 8)
link1.trvel()
3.分隔链表
from SingleLink import *
def Separarte(link, key):
small_link = SingleLink()
greater_link = SingleLink()
if not link:
return
if not link.head:
return
len_link = len(link)
f = link.head
for i in range(len_link):
if f.element >= key:
greater_link.append(f.element)
f = f.next
else:
small_link.append(f.element)
f = f.next
len_greater = len(greater_link)
n = greater_link.head
for a in range(len_greater):
small_link.append(n.element)
n = n.next
small_link.traverse()
if __name__ == '__main__':
link = SingleLink()
ls = [1,4,3,2,5,2]
for item in ls:
link.append(item)
link.traverse()
Separarte(link, 3)