基础数据结构
栈(stack)
栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。
这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,
它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,
它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
栈作为一种数据结构,是一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,
先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。
栈具有记忆作用,对栈的插入与删除操作中,不需要改变栈底指针。
- 特性:先进后出的数据结构
# 应用:每个 web 浏览器都有一个返回按钮。当你浏览网页时,这些网页被放置在一个栈中(实际是网页的网址)。
你现在查看的网页在顶部,你第一个查看的网页在底部。如果按‘返回’按钮,将按相反的顺序浏览刚才的页面。
# 使用python代码实现一个栈
- Stack() 创建一个空的新栈。 它不需要参数,并返回一个空栈。
- push(item)将一个新项添加到栈的顶部。它需要 item 做参数并不返回任何内容。
- pop() 从栈中删除顶部项。它不需要参数并返回 item 。栈被修改。
- peek() 从栈返回顶部项,但不会删除它。不需要参数。 不修改栈。
- isEmpty() 测试栈是否为空。不需要参数,并返回布尔值。
- size() 返回栈中的 item 数量。不需要参数,并返回一个整数。
class Stack():
def __init__(self):
self.items = []
def push(self,item):
self.items.append(item)
def pop(self):
return self.items.pop()
def peek(self):
return len(self.items) - 1
def isEmpty(self):
return self.items == []
def size(self):
return len(self.items)
stack = Stack()
stack.push(1)
stack.push(2)
stack.push(3)
print('栈顶元素下标:',stack.peek())
print(stack.isEmpty())
print('元素个数:',stack.size())
print(stack.pop())
print(stack.pop())
print(stack.pop())
队列 (queue)
- 队列:先进先出
- 应用场景:
- 我们的计算机实验室有 30 台计算机与一台打印机联网。当学生想要打印时,
他们的打印任务与正在等待的所有其他打印任务“一致”。第一个进入的任务是先完成。
如果你是最后一个,你必须等待你前面的所有其他任务打印。
# 使用python代码实现一个队列
- Queue() 创建一个空的新队列。 它不需要参数,并返回一个空队列。
- enqueue(item) 将新项添加到队尾。 它需要 item 作为参数,并不返回任何内容。
- dequeue() 从队首移除项。它不需要参数并返回 item。 队列被修改。
- isEmpty() 查看队列是否为空。它不需要参数,并返回布尔值。
- size() 返回队列中的项数。它不需要参数,并返回一个整数。
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 size(self):
return len(self.items)
q = Queue()
q.enqueue(1)
q.enqueue(2)
q.enqueue(3)
print(q.dequeue())
print(q.dequeue())
print(q.dequeue())
# 面试题
- 烫手的山芋
- 烫手山芋游戏介绍:6个孩子围城一个圈,排列顺序孩子们自己指定。第一个孩子手里有一个烫手的山芋,
需要在计时器计时1秒后将山芋传递给下一个孩子,依次类推。规则是,在计时器每计时7秒时,手里有山芋的孩子退出游戏。
该游戏直到剩下一个孩子时结束,最后剩下的孩子获胜。请使用队列实现该游戏策略,排在第几个位置最终会获胜。
# 解题思路
- 让手里有山芋的孩子永远排在队列的头部
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 size(self):
return len(self.items)
kids = ['A','B','C','D','E','F']
queue = Queue()
for kid in kids:
queue.enqueue(kid) #A对头F队尾
while queue.size() > 1:
for i in range(6): #每循环一次,山芋传递一次,手里有山芋的孩子永远在对头位置
kid = queue.dequeue()
queue.enqueue(kid)
queue.dequeue()
print('获胜的选手是:',queue.dequeue())
for a in range(len(kids)):
if kids[a] == kid:
print('排在第:%d会获胜'%a)
# 执行结果
获胜的选手是: E
排在第:4会获胜
# 面试题 使用两个队列实现一个栈
class Queue():
def __init__(self):
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)
alist = [1,2,3,4,5]
q1 = Queue()
for i in alist:
q1.enqueue(i)
q2 = Queue()
while q1.size() > 0:
#将q1中的n-1个值取出放入到q2中
while q1.size() > 1:
item = q1.dequeue()
q2.enqueue(item)
print(q1.dequeue())
q1,q2 = q2,q1
双端队列 ( deque )
同队列相比,有两个头部和尾部。可以在双端进行数据的插入和删除,提供了单数据结构中栈和队列的特性.
# 用python代码实现一个双端队列
- Deque() 创建一个空的新 deque。它不需要参数,并返回空的 deque。
- addFront(item) 将一个新项添加到 deque 的首部。它需要 item 参数 并不返回任何内容。
- addRear(item) 将一个新项添加到 deque 的尾部。它需要 item 参数并不返回任何内容。
- removeFront() 从 deque 中删除首项。它不需要参数并返回 item。deque 被修改。
- removeRear() 从 deque 中删除尾项。它不需要参数并返回 item。deque 被修改。
- isEmpty() 测试 deque 是否为空。它不需要参数,并返回布尔值。
- size() 返回 deque 中的项数。它不需要参数,并返回一个整数。
class Deque():
def __init__(self):
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()
def removeRear(self):
return self.items.pop(0)
def isEmpty(self):
return self.items == []
def size(self):
return len(self.items)
q = Deque()
q.addFront(1)
q.addFront(2)
q.addFront(3)
print(q.removeRear())
print(q.removeRear())
print(q.removeRear())
- 双端队列应用案例:回文检查
- 回文是一个字符串,读取首尾相同的字符,例如,radar toot madam。
class Deque():
def __init__(self):
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()
def removeRear(self):
return self.items.pop(0)
def isEmpty(self):
return self.items == []
def size(self):
return len(self.items)
def isHuiWen(s):
ex = True
q = Deque()
for ch in s:
q.addFront(ch)
while q.size() > 1:
if q.removeFront() != q.removeRear():
ex = False
break
return ex
print(isHuiWen('上海自来水来自海上'))
# 执行结果
True
顺序表 与 内存
- 内存在计算机的作用
- 用来存储和运算二进制的数据
- 问题:计算机如何计算1+2?
- 将1和2的二进制类型的数据加载到计算机的内存中,然后使用寄存器进行数值的预算。
- 变量的概念
- 变量可以理解为某一块内存(实际是引用的某一块内存的地址)
- 内存空间是有两个默认的属性:
- 内存空间的大小
- bit(位):一个bit大小的内存空间只能存放一位二进制的数
- byte(字节):8bit
- kb:1024byte
- 内存空间的地址
- 使用一个十六进制的数值表示
- 作用:让cup寻址
- 理解a=10的内存图(引用,指向)
- 引用:变量==》内存空间的地址
- a = 10:a变量/引用/内存空间的地址
- 指向:如果变量或者引用表示的是某一块内存空间地址的话,则该变量或者该引用指向了该块内存
- 集合中存储的元素是有顺序的,顺序表的结构可以分为两种形式:单数据类型(np.array数组)和多数据类型(列表,元组)。
- python中的列表和元组就属于多数据类型的顺序表
- 单数据类型顺序表的内存图 (内存连续开辟,每个内存空间大小一致)
- 多数据类型顺序表的内存图(内存非连续开辟)
-
顺序表的弊端:顺序表的结构需要预先知道数据大小来申请连续的存储空间,而在进行扩充时又需要进行数据的搬迁。
链表 (Linked list)
- 链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是不像顺序表一样连续存储数据,
而是每一个结点(数据存储单元)里存放下一个结点的信息(即地址)
- 相对于顺序表,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理且进行扩充时不需要进行数据搬迁。
- 使用python实现单向链表
. is_empty():链表是否为空
. length():链表长度
. travel():遍历整个链表
. add(item):链表头部添加元素
. append(item):链表尾部添加元素
. insert(pos, item):指定位置添加元素
. remove(item):删除节点
. search(item):查找节点是否存在
# 代码
class Node():
def __init__(self,item):
self.item = item
self.next = None
class Link():
def __init__(self):
#构造出一个空链表
#_head存储的只能是空或者第一个节点的地址
self._head = None
#向链表的头部插入一个节点
def add(self,item):
#创建一个新的节点
node = Node(item)
node.next = self._head
self._head = node
def travel(self):
#_head在链表创建好之后一定是不可变
cur = self._head
while cur:
print(cur.item)
cur = cur.next
def isEmpty(self):
return self._head == None
def size(self):
cur = self._head
count = 0
while cur:
count += 1
cur = cur.next
return count
def append(self,item):
node = Node(item)
#特殊情况
if self._head == None:
self._head = node
return
cur = self._head
pre = None#pre指向的是cur前一个节点
while cur:
pre = cur
cur = cur.next
pre.next = node
def search(self,item):
find = False
cur = self._head
while cur:
if cur.item == item:
find = True
break
cur = cur.next
return find
def insert(self,pos,item):
node = Node(item)
pre = None
cur = self._head
for i in range(pos):
pre = cur
cur = cur.next
pre.next = node
node.next = cur
def remove(self,item):
cur = self._head
pre = None
#删除的是第一个节点
if cur.item == item:
self._head = cur.next
return
while cur:
pre = cur
cur = cur.next
if cur.next == None:
return
if cur.item == item:
pre.next = cur.next
return
- 如何实现将单链表倒置
# 单链表(插入,删除,遍历)
class Node():
def __init__(self,item):
self.item = item
self.next = None
class Link():
def __init__(self):
self._head = None
def append(self,item):
node = Node(item)
if self._head == None:
self._head = node
return
cur = self._head
pre = None
while cur:
pre = cur
cur = cur.next
pre.next = node
def travel(self):
cur = self._head
while cur:
print(cur.item)
cur = cur.next
def remove(self,item):
cur = self._head
pre = None
#删除的是第一个节点
if cur.item == item:
self._head = cur.next
return
while cur:
pre = cur
cur = cur.next
if item == cur.item:
pre.next = cur.next
return
def reverse(self):
cur = self._head
pre = None
next_node = cur.next
while cur:
cur.next = pre
pre = cur
cur = next_node
if cur:
next_node = cur.next
self._head = pre
# 双向链表就是连续开辟三个内存空间,分别存放 数据 上个节点内存地址 下个节点内存地址
二叉树
# 使用python代码实现二叉树
class Node():
def __init__(self,item):
self.item = item
self.left = None
self.right = None
class Tree():
def __init__(self):
self.root = None
def addNode(self,item):
node = Node(item)
#如果插入第一个节点的情况
if self.root == None:
self.root = node
return
cur = self.root
q = [cur] #列表元素是我们进行遍历判断的节点
while q:
nd = q.pop(0)
if nd.left == None:
nd.left = node
return
else:
q.append(nd.left)
if nd.right == None:
nd.right = node
return
else:
q.append(nd.right)
def travel(self): #广度优先遍历
cur = self.root
q = [cur]
while q:
nd = q.pop(0)
print(nd.item)
if nd.left:
q.append(nd.left)
if nd.right:
q.append(nd.right)
def forwoar(self,root): #深度优先 前序:根左右
if root == None:
return
print(root.item)
self.forwoar(root.left)
self.forwoar(root.right)
def middle(self,root): #深度优先 前序:左根右
if root == None:
return
self.middle(root.left)
print(root.item)
self.middle(root.right)
def back(self,root): #深度优先 前序:左右根
if root == None:
return
self.back(root.left)
self.back(root.right)
print(root.item)
作 者:郭楷丰
出 处:https://www.cnblogs.com/guokaifeng/
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角
【推荐】一下。您的鼓励是博主的最大动力!
自 勉:生活,需要追求;梦想,需要坚持;生命,需要珍惜;但人生的路上,更需要坚强。
带着感恩的心启程,学会爱,爱父母,爱自己,爱朋友,爱他人。