基本数据结构
基本的数据结构参考第一章导论,下面是四种基本的线性数据结构。
1. 栈
1.1 栈的概念及应用
- 排序原则LIFO(后入先出)
- 网页的返回机制,其URL结构为栈,Word的撤销按钮均使用了栈的结构
【Python实现】
class Stack:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def push(self, item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
return self.items[len(self.items)-1]
def size(self):
return len(self.items)
【栈的应用】
def parChecker(parString):
s = Stack()
balance = True
for i in parString:
if i == "(":
s.push(i)
else:
if s.isEmpty():
balance = False
else:
s.pop()
if s.isEmpty() and balance:
return True
else:
return False
def parChecker(parString):
s = Stack()
balance = True
opens = '{[('
closers = '}])'
for i in parString:
if i in "{[(":
s.push(i)
else:
if s.isEmpty():
balance = False
else:
top = s.pop()
if opens.index(top) != closers.index(i):
balance = False
if s.isEmpty() and balance:
return True
else:
return False
def divideBy2(number):
s = Stack()
binString = ""
while number > 0:
i = number % 2
s.push(i)
number = number // 2
while not s.isEmpty():
binString += str(s.pop())
return binString
1.2 表达式转换
- 全括号表达式转换为后序,向后移动运算符
- 全括号表达式转换为前序,向前移动运算符
- 从中序到后序的通用转换法
import string
def infixToPostfix(infixExpr):
prec = {"*":3, "/":3, "+":2, "-":2, "(":1}
postString = ""
opstack = Stack()
for i in infixExpr:
if i in string.ascii_uppercase:
postString += i
elif i == "(":
opstack.push(i)
elif i == ")":
a = opstack.pop()
while a != "(":
postString += a
a = opstack.pop()
else:
while (not opstack.isEmpty()) and (prec[opstack.peek()] >= prec[i]):
postString += opstack.pop()
opstack.push(i)
while not opstack.isEmpty():
postString += opstack.pop()
return postString
2. 队列
- 队列是有序集合,添加操作发生在尾部,移除操作发生在头部。新元素从尾部进入队列,然后一直向前移动到头部,直到成为下一个被移除的元素。
- 与栈相反,队列是FIFO(先进先出)
【Python实现】
class Queue:
def __init__(self):
self.items = []
def isEmpty(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)
def JosephusProblem(nameList,number):
queue = Queue()
for i in nameList:
queue.enqueue(i)
while queue.size() > 1:
for i in range(number):
queue.enqueue(queue.dequeue())
queue.dequeue()
return queue.dequeue()
3. 双端队列
- 双端队列是与队列类似的有序集合。它有一前,一后两端,元素在其中保持自己的位置。
- 新元素既可以被添加到前端,也可以被添加到后端。
- 已有的元素也能从任意一端移除。
【Python实现】
class Deque:
def __init__(self):
self.items = []
def isEmpty(self):
return self.items == []
def addFront(self, item):
self.items.insert(0, item)
def addRear(self, item):
self.items.append(item)
def removeFront(self):
return self.items.pop(0)
def removeRear(self):
return self.items.pop()
def size(self):
return len(self.items)
def palchecker(aString):
chardeque = Deque()
for ch in aString:
chardeque.addRear(ch)
stillEqual = True
while chardeque.size() > 1 and stillEqual:
first = chardeque.removeFront()
last = chardeque.removeRear()
if first != last:
stillEqual = False
return stillEqual
4. 链表
- 与前面的顺序表不同,链表是无序结构,连接了内存中的不相连的内存数据。
- 链表中包含两块信息,一块存放数据,另一块指向下一块数据的地址,形成链式结构
4.1 链表的实现
【节点实现】
class Node:
def __init__(self, initdata):
self.data = initdata
self.next = None
- 无序列表是基于节点集合来构建的,每一个节点都通过显式的引用指向下一个节点;
- 重要的一点,列表类并不包含任何节点对象,而只有指向整个链表结构中第一个节点的引用。
- isEmpty() 判断链表是否为空
- add() 从头部插入元素
- append() 从尾部插入元素
- insert() 指定元素位置插入元素
- remove() 从链表中移除元素(移除第一个查到的相同元素)
- length() 返回链表的长度
- search() 查找链表中是否存在某元素
- travel() 遍历打印链表
class SingleLinkList:
def __init__(self):
self.head = None
def isEmpty(self):
return self.head == None
def add(self, item):
"""头插法"""
temp = Node(item)
temp.next = self.head
self.head = temp
def append(self, item):
"""尾插法"""
node = Node(item)
if self.isEmpty():
self.head = node
else:
current = self.head
while current.next != None:
current = current.next
current.next = node
def insert(self, pos, item):
"""
:param pos: 要插入的位置
:param item: 插入的元素
:return: None
"""
if pos <= 0:
self.add(item)
elif pos > (self.length() - 1):
self.append(item)
else:
pre = self.head
count = 0
while count < pos - 1:
count += 1
pre = pre.next
node = Node(item)
node.next = pre.next
pre.next = node
def remove(self, item):
current = self.head
pre = None
found = False
while not found:
if current.data == item:
found = True
else:
pre = current
current = current.next
if pre == None:
self.head = current.next
else:
pre.next = current.next
def length(self):
current = self.head
count = 0
while current != None:
count += 1
current = current.next
return count
def search(self, item):
current = self.head
while current != None:
if current.data == item:
return True
else:
current = current.next
return False
def travel(self):
current = self.head
while current != None:
print(current.data)
current = current.next
if __name__ == "__main__":
sll = SingleLinkList()
print(sll.isEmpty())
print(sll.length())
sll.insert(0, 100)
sll.add(100)
sll.travel()
sll.remove(100)
print("===========")
sll.travel()
print(sll.isEmpty())
4.2 链表与顺序表
链表失去了顺序表随机读取的优点,同时链表由于附加有地址信息,相应的空间消耗也会增大,但是对于一个较大的数据,链表能够灵活的调用不连续的内存空间,使用相对灵活。
操作 | 链表 | 顺寻表 |
访问元素 | \(O(n)\) | \(O(1)\) |
头部插入 | \(O(1)\) | \(O(n)\) |
尾部插入 | \(O(n)\) | \(O(1)\) |
中间插入 | \(O(n)\) | \(O(n)\) |