推荐个网站,学习数据结构时可以到 visualgo这个网站,感受认识操作一些数据结构的整个动态执行过程,当我们在用代码实现其数据结构的时候,它能给我们带来一些code的思路。
本文涉及的内容是用python实现线性结构:栈、单链表、双链表和队列,关于怎么用python实现非线性结构的数据结构,请听下回分解。
栈(stack),它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。
栈允许进行插入和删除操作的一端称为栈顶(top),另一端为栈底(bottom);栈底固定,而栈顶浮动;栈中元素个数为零时称为空栈。插入一般称为进栈(PUSH),删除则称为退栈(POP)。
python代码实现
class Stack(object):
def __init__(self,limit = 10):
self.stack = []
self.limit = limit
def push(self,data):
if len(self.stack) >= self.limit:
raise IndexError("超出栈顶容量")
#List append往左加元素
self.stack.append(data)
def pop(self):
if self.stack:
return self.stack.pop()
else:
raise IndexError("已经空栈")
def peek(self):
if self.stack:
return self.stack[-1]
def is_empty(self):
#bool()若没有参数,返回False,判断栈是否为空
return not bool(self.stack)
def size(self):
#查看栈中有几个元素
return len(self.stack)
#以上即是实现一个栈的基本代码
#作业(用栈解决括号匹配问题)
"""算法思路,循环字符串的每一个字符("("或")"),如果是(,直接入栈
如果是")",先判断栈为不为空,若为空,返回括号匹配错误,若不为空,
栈pop出一个元素,字符串的字符循环完之后,再判断栈为不为空,若不为空,
返回括号匹配错误,若不为空,返回括号匹配正确
"""
def balanced_parentheses(str):
stack = Stack(len(str))
for char in str:
if char == "(":
stack.push(char)
elif char == ")":
if stack.size() == 0:
return False
stack.pop()
return stack.is_empty()
if __name__ == "__main__":
examples = ["(())","())","(()))"]
for example in examples:
print(balanced_parentheses(example))
链表(linked_list)是物理存储单元上非连续的、非顺序的存储结构,数据元素的逻辑顺序是通过链表的指针地址实现,每个元素包含两个结点,一个是存储元素的数据域 (内存空间),另一个是指向下一个结点地址的指针域。根据指针的指向,链表能形成不同的结构,例如单链表,双向链表,循环链表等。而单链表中的每个节点只包含一个数据域和一个指针域(尾)。
想获取对链表的更多认识可戳这篇文章数据结构中的链表,你知道多少?
python代码实现
class Node:
#初始化链点
def __init__(self,data):
self.data = data
self.next = None
class Link_List:
#初始化链表,注意初始化链表时head可能不存在
def __init__(self,head = None):
self.head = head
#链表的添加功能
def append(self,new_element):
#current当前的
current = self.head
#当头部节点存在
if self.head:
while current.next:
current = current.next
current.next = new_element
#当头部节点不存在
else:
self.head = new_element
def is_empty(self):
#判断链表为不为空,只需要判断head为不为空
return not self.head
def get_length(self):
#求链表的长度
temp =self.head
length = 0
while temp != None:
length = length + 1
temp = temp.next
return length
def insert(self,position,new_element):
#在链表指定索引处插入元素
if position < 0 or position > self.get_length():
raise IndexError("插入位置超出范围")
temp = self.head
#当插入位置在第一位时候,把head变为新节点
if position == 0:
new_element.next = temp
self.head = new_element
return
i = 0
while i < position:
pre = temp
temp = temp.next
i+=1
pre.next = new_element
new_element.next = temp
def remove(self,position):
#删除指定索引的链表元素
if position < 0 or position > self.get_length():
raise IndexError("要删除的链表元素超出范围")
i = 0
temp = self.head
while temp != None:
if position == 0:
self.head = temp.next
temp.next = None
return
pre = temp
temp = temp.next
i+=1
if i == position:
pre.next = temp.next
temp.next = None
return
def print_list(self):
#打印链表元素
temp = self.head
while temp is not None:
print(temp.data)
temp = temp.next
def initlist(self,data_list):
#将列表转为链表
#创建头结点
self.head = Node(data_list[0])
temp = self.head
#逐个为列表中的元素创建结点
for i in data_list[1:]:
node = Node(i)
temp.next = node
temp = temp.next
def reverse(self):
#将链表反转
"""
假设存在链表 1 → 2 → 3 → Ø,我们想要把它改成 Ø ← 1 ← 2 ← 3。
在遍历列表时,将当前节点的 next 指针改为指向前一个元素。
由于节点没有引用其上一个节点,因此必须事先存储其前一个元素。
在更改引用之前,还需要另一个指针来存储下一个节点。不要忘记在最后返回新的头引用!
"""
prev = None
current = self.head
while current:
next_node = current.next
current.next = prev #遍历每一个结点,使其next指向前一个结点
prev = current
current = next_node
self.head = prev
#交换两个数据特定的链表元素
def swapNodes(self,node1,node2):
#传入的node1和node2是要交换的链表元素的数据,而不是链表元素
prevD1 = None
prevD2 = None
#先判断要实行元素交换的链表是否为空,空退出
if self.is_empty():
return
else:
#判断要交换的元素数据是否相同,相同退出
if node1 == node2:
return
else:
#根据node1和node2的值找出要交换的两个链表元素
D1 = self.head
while D1 != None and D1.data != node1:
prevD1 = D1
D1 = D1.next
D2 = self.head
while D2 != None and D2.data != node2:
prevD2 = D2
D2 = D2.next
#如果要交换的D1节点是head,做如下交换
if prevD1 != None:
prevD1.next = D2
else:
self.head = D2
#如果要交换的D2节点是head,做如下交换
if prevD2 != None:
prevD2.next = D1
else:
self.head = D1
#如果要交换的D1和D2均不是head,做如下交换
temp = D1.next
D1.next = D2.next
D2.next = temp
if __name__ == "__main__":
link_list = Link_List()
link_list.append(Node(5))
link_list.append(Node(4))
link_list.append(Node(3))
link_list.append(Node(2))
link_list.append(Node(1))
print("交换前")
link_list.print_list()
link_list.swapNodes(1,4)
print("交换后")
link_list.print_list()
双向链表(Double_linked_list)也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向它的前一个结点和他的后一个结点。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。
python代码实现
class Node():
def __init__(self,data):
#双链表对比单链表,其中的元素多了一个头指针(prev)
self.data = data
self.next = None
self.prev = None
class DLinkList():
"""双链表它不是循环链表"""
def __init__(self):
self._head = None
#判断链表是否为空
def is_empty(self):
return not self._head
#获取链表长度
def get_length(self):
count = 0
current = self._head
while current:
count += 1
current = current.next
return count
#打印链表中的元素
def print_node(self):
current = self._head
while current != None:
print(current.data)
current = current.next
print("到尽头了")
#链表头部添加元素
def add(self,data):
new_node = Node(data)
if self.is_empty():
self._head = new_node
else:
new_node.next = self._head
self._head.prev = new_node
self._head = new_node
#链表尾部插入数据
def append(self,data):
new_node = Node(data)
#循环找到链表尾部元素
current = self._head
while current != None:
current = current.next
current.next = new_node
new_node.prev = current
#查询特定数据的链表元素是否存在
def search(self,data):
current = self._head
while current != None:
if current.data == data:
return True
current = current.next
return False
#往特定位置插入链表元素
def insert(self,position,data):
#如果position <= 0,均往链表首插入
if position <= 0:
self.add(data)
#如果position >= 链表长度,均往链表尾插入
elif position >= self.get_length:
self.append(data)
#如果position既不 <= 0和 >= 0,则循环找到position-1的元素,让其尾指针
#指向插入的元素,让其下一个节点头指针指向插入的元素,而插入的元素的头指针
#指向位置position-1的元素,尾指针指向指向position-1的元素的下一个元素
else:
new_node = Node(data)
current = self._head
count = 0
while count < (position-1):
count += 1
current = current.next
new_node.prev = current
new_node.next = current.next
current.next = new_node
current.next.prev = new_node
def remove(self,data):
#删除指定数据的链表元素
#如果链表为空则删除错误
if self.is_empty:
return
else:
current = self._head
if current.data == data:
if current.next == None:
self._head = None
else:
current.next.prev = None
self._head = current.next
return
while current != None:
current = current.next
if current.data == data:
current.prev.next = current.next
current.next.prev = current.prev
break
队列 (queue) 是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。
队列有两种实现形式,分为两种:数组和链表。
python用数组实现队列
#使用数组构造队列
class Queue1():
def __init__(self):
self.entries = []
self.length = 0
self.front = 0
#添加元素
def enqueue(self,data):
self.entries.append(data)
self.length += 1
#取元素
def dequeue(self):
self.length -= 1
dequeue = self.entries[self.front]
self.front += 1
self.entries = self.entries[self.front:]
return dequeue
#查看队列头部的元素
def peek(self):
return self.entries[0]
python用链表实现队列
class Node():
def __init__(self,data,next = None):
self.data = data
self.next = next
#使用链表构造队列
class Queue2():
def __init__(self):
self.head = None
self.rear = None
def is_empty(self):
return self.head is None
#往队列尾添加一个元素
def enqueue(self,data):
p = Node(data)
if self.is_empty():
self.head = p
self.rear = p
else:
self.rear.next = p
self.rear = p
#往队列头获取一个数据
def dequeue(self):
if self.is_empty():
print("队列为空")
else:
result = self.head #result为队列头部元素
self.head = self.head.next #改变队列头部指针位置
return result #返回队列头部元素(获取结果)
#查看队列头部的元素
def peek(self):
if self.is_empty():
print("队列为空")
else:
return self.head.data
#打印队列的元素
def print_queue(self):
print("队列:")
myqueue_item = []
temp = self.head
while temp != None:
myqueue_item.append(temp.data)
temp = temp.next
print(myqueue_item)
#用链表创建的队列实现队列的基本功能
if __name__ == "__main__":
queue = Queue2()
queue.enqueue(21)
queue.enqueue(35)
queue.enqueue(58)
queue.enqueue(13)
queue.peek()
queue.dequeue()
queue.print_queue()