6.数据结构
目录
数据结构
1.时间复杂度
1.时间复杂度:大O表示 -- O(f(n))
量化算法需要的操作或者执行步骤的数量。
2.基本操作执行次数的函数 T(n):
如果T(n)=5n^2+27n+1005,随着 n 变大,n^2 这项变得越来越重要,我们可以忽略其他项,只关注5n^2,系数 5 也变得不重要。我们说,T(n) 具有的数量级为 f(n)=n^2,或者 O( n^2 )
3.常见的时间复杂度比较:
O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)
2.线性数据结构
一.线性数据结构
- 我们从四个简单但重要的概念开始研究数据结构。栈,队列,deques(双向队列), 列表是一类数据的容器,它们数据元素之间的顺序由添加或删除的顺序决定。一旦一个数据元素被添加,它相对于前后元素一直保持该位置不变。诸如此类的数据结构被称为线性数据结构。
- 线性数据结构有两端,有时被称为左右,某些情况被称为前后。你也可以称为顶部和底部,名字都不重要。将两个线性数据结构区分开的方法是添加和移除元素的方式,特别是添加和移除元素的位置。例如一些结构允许从一端添加元素,另一些允许从另一端移除元素。
栈 -- 先进后出,后进先出
概念:栈(有时称为“后进先出栈”)是一个元素的有序集合,其中添加移除新元素总发生在同一端。这一端通常称为“顶部”。与顶部对应的端称为“底部”。栈的底部很重要,因为在栈中靠近底部的元素是存储时间最长的。最近添加的元素是最先会被移除的
python实现栈:
# 列表实现栈
class Stack():
# 创建一个空栈
def __init__(self):
self.items = []
# 进栈添加数据 -- 追加数据
def push(self,item):
self.items.append(item)
# 出栈移除数据 -- 从列表最后移除数据
def pop(self):
return self.items.pop()
# 判断栈是否为空
def isEmpty(self):
return self.items == []
# 栈长度
def length(self):
return len(self.items)
# 测试:
stack = Stack() # 实例化一个栈
alist = [1,2,3,4]
for item in alist:
stack.push(item)
for i in range(stack.length()):
print(stack.pop()) # 4 3 2 1
队列 -- 先进先出
概念:队列是项的有序结合,其中添加新项的一端称为队尾,移除项的一端称为队首。当一个元素从队尾进入队列时,一直向队首移动,直到它成为下一个需要移除的元素为止。最近添加的元素必须在队尾等待。集合中存活时间最长的元素在队首,这种排序成为 FIFO,先进先出,也被成为先到先得。
python实现队列:
# 特性:先进先出
# 入队列:从队尾部向头部添加
# 出队列:从头部出队列
class Queue():
# 创建一个队列
def __init__(self):
self.items = []
# 入队列
def enqueue(self,item):
self.items.insert(0,item)
# 出队列
def dequeue(self):
return self.items.pop()
# 判断队列是否为空
def isEmpty(self):
return self.items == []
# 队列长度
def length(self):
return len(self.items)
# 测试:
queue = Queue() # 实例化一个队列
alist = [1,2,3,4]
for item in alist:
queue.enqueue(item)
for i in range(queue.length()):
print(queue.dequeue())
1.队列的应用案例-烫手的山芋
烫手山芋游戏介绍:
6个孩子围城一个圈,排列顺序孩子们自己指定。第一个孩子手里有一个烫手的山芋,需要在计时器计时1秒后将山芋传递给下一个孩子,依次类推。规则是,在计时器每计时7秒时,手里有山芋的孩子退出游戏。该游戏直到剩下一个孩子时结束,最后剩下的孩子获胜。请使用队列实现该游戏策略,排在第几个位置最终会获胜?
分析: 循环报数,每到第6个人,剔除队列,直到只剩最后一人
python代码实现:
class Queue():
def __init__(self):
self.items = []
# 进入队列
def enqueue(self,item):
self.items.insert(0,item)
# 出队列
def dequeue(self):
return self.items.pop()
# 判断是否为空
def isEmpty(self):
return self.items == []
# 队列长度
def length(self):
return len(self.items)
# 实例化一个队列对象
queue = Queue()
# 孩子列表
kids = list(range(1,7))
print(kids)
# 添加到队列
for i in kids:
queue.enqueue(i)
# 循环移除队列,直到剩最后一人
while queue.length() > 1:
for i in range(6):
# 队列循环
item = queue.dequeue()
queue.enqueue(item)
# 移除第6个孩子
queue.dequeue()
print('最后获胜者:',queue.dequeue())
2.两个队列实现一个栈的效果
# 队列 先进先出 --> 栈 后进先出
class Queue():
def __init__(self):
self.items = []
# 进入队列
def enqueue(self,item):
self.items.insert(0,item)
# 出队列
def dequeue(self):
return self.items.pop()
# 判断是否为空
def isEmpty(self):
return self.items == []
# 队列长度
def length(self):
return len(self.items)
# 实例化两个队列
q1 = Queue()
q2 = Queue()
lis = [1,2,3,4]
# 入队列
for i in lis:
q1.enqueue(i)
# 循环终止条件
while q1.length() > 0:
for i in range(q1.length()-1):
item = q1.dequeue()
q2.enqueue(item)
print(q1.dequeue())
# 队列交换
q1,q2 = q2,q1
3.两个栈实现一个队列效果
# 栈 后进先出 --> 队列 先进先出
class Stack():
def __init__(self):
self.items = []
# 进栈
def push(self,item):
self.items.append(item)
# 出栈
def pop(self):
return self.items.pop()
# 判断是否为空
def isEmpty(self):
return self.items == []
# 栈长度
def length(self):
return len(self.items)
# 实例化两个栈对象
s1 = Stack()
s2 = Stack()
lis = [1,2,3,4]
# 添加栈
for i in lis:
s1.push(i)
# 改变栈顺序 -- 后进先出
for i in range(s1.length()):
item = s1.pop()
s2.push(item)
# 循环遍历s2
for i in range(s2.length()):
print(s2.pop())
双端队列
特性: 可以从任意端(队首,队尾)添加,也可以从任意端移除
python代码实现:
class Deque():
# 创建一个空队列
def __init__(self):
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 is_empty(self):
return self.items == []
# 队列长度
def length(self):
return len(self.items)
回文检索 -- 设计程序,检测一个字符串是否为回文
回文:回文是一个字符串,读取首尾相同的字符,例如,radar toot madam
# 回文检索
def jiance(str):
# 实例化双端队列对象
deque = Deque()
# 添加队列
for i in str:
deque.add_rear(i)
# 判断是否是回文
is_huiwen = True
while (deque.length() > 1) and is_huiwen:
# 首字符
front = deque.remove_front()
# 尾字符
rear = deque.remove_rear()
# 判断首尾字符是否相等
if front != rear:
is_huiwen = False
return is_huiwen
# 测试
str = 'radar'
print(jiance(str)) # True
3.链表
链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样连续存储数据,而是每一个结点(数据存储单元)里存放下一个结点的信息(即地址)
单向链表
单向链表也叫单链表,是表中最简单的一种形式,它的每个节点包含两个域,一个信息域(元素域)和一个链接域。这个链接域指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。
python代码实现:
# 封装节点
class Node():
def __init__(self,item):
self.item = item # 元素域
self.next = None # 连接域
# 封装链表
class Link():
# 1.链表的头
def __init__(self):
self._head = None
# 2.判断链表是否为空
def is_empty(self):
return self._head is None
# 3.链表长度
def length(self):
cur = self._head
count = 0
while cur:
count += 1
cur = cur.next
return count
# 4.向链表头部添加节点元素
def add_front(self,item):
node = Node(item)
node.next = self._head
self._head = node
# 5.向链表尾部添加节点元素
def add_rear(self,item):
node = Node(item)
cur = self._head
# 判断是否为空链表
if self.is_empty():
node.next = self._head
self._head = node
return
# 循环链表找到最后一个节点元素
while cur:
pre = cur
cur = cur.next
node.next = None
pre.next = node
# 6.遍历链表
def trasersal(self):
if self.is_empty():
print('链表中没有数据')
return # 终止程序
# 表头位置不要动,重新赋值
cur = self._head
while cur:
print(cur.item)
cur = cur.next
# 7.查找节点元素是否存在
def search(self,item):
cur = self._head
# 判断是否为空链表
if cur is None:
return False
while cur:
if cur.item == item:
return True
cur = cur.next
return False
# 8.指定位置添加元素
def add_index(self,pos,item):
node = Node(item)
if pos > self.length():
print('超出链表索引位置,不能添加')
return # 终止程序
if pos == 0: # 从头添加
node.next = self._head
self._head = node
sum = 1 # 当前链表位置
cur = self._head
while cur:
pre = cur
cur = cur.next
if pos == sum:
pre.next = node
node.next = cur
sum += 1
# 9.删除链表节点元素
def remove(self,item):
pre = None # cur前一个节点
cur = self._head
while cur:
if cur.item == item:
if pre is None: # 删除的是第一个节点元素
self._head = cur.next
return # 终止程序
pre.next = cur.next # 删除非第一个节点元素
pre = cur
cur = cur.next
print('链表中没有你要删除的元素')
# 10.反转链表
def reverse(self):
if self.is_empty():
print('链表中没有数据,不能反转')
return
pre = None # 前一个节点
cur = self._head # 当前节点
nex = cur.next # 后一个节点
while cur:
cur.next = pre # 当前节点的下一个节点是前一个节点
pre = cur
cur = nex
if cur is not None:
nex = nex.next
self._head = pre # 最后,把链表头放到链表最后一个节点
# 测试
# 实例化链表对象
link = Link()
print(link.is_empty())
link.trasersal()
link.add_front(1)
link.add_front(2)
link.add_rear(66)
print(link.search(2))
link.add_index(5,66)
link.remove(66)
link.reverse()
link.trasersal()
print(link.length())