python 下的数据结构与算法---4:线形数据结构,栈,队列,双端队列,列表
目录:
前言
1:栈
1.1:栈的实现
1.2:栈的应用:
1.2.1:检验数学表达式的括号匹配
1.2.2:将十进制数转化为任意进制
1.2.3:后置表达式的生成及其计算
2:队列
2.1:队列的实现
2.2:队列的应用之囚徒问题
3:双端队列
3.1:双端队列的实现
3.2:双端队列的应用之回文检测
4:列表
3.1:链表的实现
前言
线性数据结构有四种:栈(stack),队列(queue),双端队列(deque),列表(list)
线性数据结构就是一群数据的集合,数据的位置和其加入的先后顺序有关,并且由此将其看为有两端,头(top)与尾(rear)【其中认为头是最先加入的数据,尾是最后加入的数据】
一:栈(stack)
1:栈的构造
栈可以看成是堆盘子,只能从上端加入以及从上端取出,也就是只能从一端对其进行操作。对应到线形结构就是只能在尾部对其进行加入与删除的数据结构。简称LIFO(last in first out),即是后进先出。
习惯上我们把栈尾部叫做栈顶(TOP),加入数据叫做压栈(push),删除叫做出栈(pop)
要注意一点的是,此处的栈顶其实是list的队尾,理论上将两个top对应起来也是简单的,但是前面讲过list的insert(0,i)与pop(0)都是O(n)的操作,而末尾的append(i)与pop(i)都是O(1),故依旧选择后者。
class Stack:
def __init__(self,*args):
self.cstack = [] #c:construct
for i in args:
self.cstack.append(i)
def push(self,x): #压栈
self.cstack.append(x)
def size(self): #查看元素个数
return len(self.cstack)
def pop(self): #出栈
if self.size()>0:
return self.cstack.pop()
else:
print('Sorry, this is an empty stack')
def peek(self): #检查栈顶元素是什么
if self.size()>0:
return self.cstack[len(self.cstack)-1]
else:
return 'empty stack'
栈的实现
由上我们可以看出,其操作都是基于list的,结合昨天的表可以知道:
Stack = Stack(1,2,3,4,5…,n) O(n)
Push,pop,size,peek O(1)
2:栈的应用:
1]: 检测数学表达式的括号是否配对
遍历输入的表达式,遇到(后压入栈,遇到)后将栈顶(出栈,若最后为空栈则是匹配成功的,其他 [ ]与 { }同理
from stackType_01 import Stack while True:
stack = Stack()
str = input('input the arithmetic expression:')
if len(str) == 0:
print('input something')
else:
for i in str:
if i in '({[': #!!!
stack.push(i)
elif i in ')}]':
stack.pop()
if stack.size()==0:
print('It is a balanced arithmetic expression')
else:
print('not a balanced arithmatic expression')
检查数学表达式括号配对
2]:将一个十进制的数转化为任意进制的数
原理:首先,n进制就是从0开始到n-1,若n>9则从A开始分别表示10……
其次,假设输入的十进制是n,想要转化为x进制,此时首先对n除以x取余,将余数放入栈,而后将n整除x后的数作为下一个n重复上面两个步骤直到n整除值为零,最后栈里面的数的逆序就是结果了:
e.g:十进制转二进制
from stackType_01 import Stack
deci = int(input('input the number:'))
base = int(input('input the system you want to transfer to:')) def trans(deci,base):
flag = '0123456789ABCDEF'
stack = Stack()
while deci//base > 0:
stack.push(flag[deci%base])
deci //= base
stack.push(flag[deci])
print(stack.cstack) trans(deci,base)
十进制转化为任意进制
3]:后置,前置,中置表达式
即是把运算符放到最近的括号外(前置放括号前面,后置放后面)。
将普通表达式转化为后置表达式的原理:创建一个list以及一个stack,遇到’(,+-*/’ 都压入栈,遇到数字放入list,遇到‘)‘就把栈里面直到最近的一个’(‘中的运算符pop入list,如下图所示:
遇到后置表达式的运算原理:创建一个栈,开始遍历后置表达式,如果是数字就压入栈,如果是运算符就出栈两个数进行对应的运算后得到一个数并将其压入栈。
#python提供的eval函数能够对string型运算表达式进行运算并返回值
# -*- coding:utf-8 -*-
# from stackType_01 import Stack
import stackType_01
def ToPostfix(expression):
L = []
stack = stackType_01.Stack()
for i in expression:
if i in '(+-*/':
stack.push(i)
elif i == ')':
while stack.peek() != '(':
L.append(stack.pop())
stack.pop()
else:
L.append(i)
print('postfix:',''.join(L))
return L def calpostfix(stt):
stack = stackType_01.Stack()
for i in stt:
if i in '+-*/':
pop1 = stack.pop()
pop2 = stack.pop()
temp = pop2+i+pop1
stack.push(str(eval(temp)))
else:
stack.push(i)
print('calresult:',stack.peek()) expression = list(input('plz input the expression with balanced parentheses:'))
calpostfix(ToPostfix(expression))
转化为后置表达式以及后置表达式的运算
二:队列(queue)
1:队列的实现
区别于栈的只能够从一边进行出,队列是一端进,一段出,就像有一截水管,从一端先进的从另一端先出,这叫FIFO(first in first out),即是先进先出。
习惯上我们把加入数据叫做入队(enqueue),删除数据叫离队(dequeue)。
由于还是用list来实现queue,故说明下队首与list位置的关系,为了模拟左进右出的管道,我们把list尾部实现为queue的对首,即是即将删除的数据。
class Queue: # right is the front
def __init__(self,*args):
self.item = []
for i in args:
self.item.insert(0,i) def size(self):
return len(self.item) def is_empty(self):
if self.size() == 0:
return True
else:
return False
def enqueue(self,*arg):
for i in arg:
self.item.insert(0,i) def dequeue(self):
if self.size() > 0:
return self.item.pop()
else:
print('empty queue, cannot dequeue anymore') # que = Queue(1,2,3)
# que.enqueue(4,5)
# print(que.item)
# print(que.dequeue())
# print(que.dequeue())
# print(que.size())
队列的实现
显然,dequeue方法为O(n),enqueue方法为O(1)
2:队列的应用
囚徒问题:n个犯人围城圈,从头开始数一个确定的数,到达这个数后此人出圈,他下个人继续从1开始数,直到最后只剩下一个人,用程序模拟此过程:
实现原理:用队列实现一个圆圈的模拟,从队首开始,没经过了它就把计数器flag加一而后把此元素删除并且放到队尾,直到遇到flag为判别数的人,将此人删掉,flag置一后又开始直到只剩下一个人
from Queue_05 import Queue
names = input('plz input the names(with blank betwwwn them):')
juge = int(input('plz input the judge number:'))
flag = 1
queue = Queue()
for i in names.split(" "):
queue.enqueue(i) while queue.size() != 1:
if flag != juge:
queue.enqueue(queue.dequeue())
flag+=1
else:
queue.dequeue()
flag=1 print(queue.item)
囚徒问题
三:双端队列(deque)
1:双端队列的实现
区别于队列的一端进一端出,双端队列是在两端都可以进出的数据结构。
我们把list右端作为其前端,且分别把队头,队尾的增删操作方法为add_front / rear,remove_front / rear
class Deque: # right is the front
def __init__(self,*args):
self.item = []
for i in args:
self.item.insert(0,i) def __len__(self):
return len(self.item)
def size(self):
return len(self.item) def is_empty(self):
if self.size() == 0:
return True
else:
return False
def add_front(self,*arg):
for i in arg:
self.item.append(i) def add_rear(self,*arg):
for i in arg:
self.item.insert(0,i) def remove_front(self):
if self.size() > 0:
return self.item.pop()
else:
print('empty deque, cannot dequeue anymore') def remove_rear(self):
if self.size() > 0:
return self.item.pop(0)
else:
print('empty deque, cannot dequeue anymore')
双端队列的实现
注意,此地增删可同时n个数,front端的增删为O(n),rear端的为O(n^2)
2:应用
回文检验:原理,从队列两端分别删除元素来进行比较,直到剩下不多于一个数且都全部匹配则为回文
from Deque_07 import Deque
flag = 1
expression = input('plz input the string:')
deque = Deque()
for i in expression:
deque.add_rear(i) while deque.size() != 1 or 0:
a = deque.remove_front()
b = deque.remove_rear()
if a!=b:
flag = 0
break if flag:
print('yes, it is huiwen')
else:
print('nout a huiwen string')
回文检测
四:列表(list)
原本的list,python是有的,不过在这里我们要实现一个基于相对位置有序的列表,也就是C语言中我们所说的链表(linked list)
设计思路:拆分出来看,每个节点(node)都是一个值和一个指向下个节点的变量构成的,总体上来看,有first与last两个变量分别指向第一个节点和最后一个节点。
class LinkedList: class __Node:
def __init__(self, item, next = None):
self.item = item
self.next = next def getItem(self):
return self.item def setItem(self, item):
self.item = item def setNext(self,next):
self.next = next def getNext(self):
return self.next def __init__(self,contents=[]):
self.first = LinkedList.__Node(None,None)
self.last = self.first
self.numItems = 0
for i,e in enumerate(contents):
if i == 1:
self.first = self.first.getNext()
self.append(e) def append(self,item):
node = LinkedList.__Node(item)
self.last.setNext(node)
self.last = node
self.numItems += 1 def __getitem__(self,index):
if index >= 0 and index < self.numItems:
cursor = self.first.getNext()
for i in range(index):
cursor = cursor.getNext()
return cursor.getItem() raise IndexError("LinkedList index out of range") def __setitem__(self,index,val):
if index >= 0 and index < self.numItems:
cursor = self.first.getNext()
for i in range(index):
cursor = cursor.getNext()
cursor.setItem(val)
return raise IndexError("LinkedList assignment index out of range") def __add__(self,other):
if type(self) != type(other):
raise TypeError("Concatenate undefined for " + str(type(self)) + " + " + str(type(other)))
result = LinkedList()
cursor = self.first.getNext()
while cursor != None:
result.append(cursor.getItem())
cursor = cursor.getNext() cursor = other.first.getNext() while cursor != None:
result.append(cursor.getItem())
cursor = cursor.getNext()
return result def insert(self,index,item):
cursor = self.first
if index < self.numItems:
for i in range(index):
cursor = cursor.getNext() node = LinkedList.__Node(item, cursor.getNext())
cursor.setNext(node)
self.numItems += 1
else:
self.append(item) linkedlist = LinkedList([1,2,3,4,5])
linkedlist2 = LinkedList([9,8,7,6])
print(linkedlist.first.item) print(linkedlist[2])
linkedlist.append('append')
linkedlist.insert(2,'insert')
linkedlist += linkedlist2
for i in linkedlist:
print(i)
链表的实现
其实这个程序有点小问题不知你发现没有,我也是刚发现的,其实就是first指标其实一直指向了一个空节点。通过实例.getnext()才能够获得真正的第一个节点。
将(*)部分改成如下即可:
for i,e in enumerate(contents):
if i == 1:
self.first = self.first.getNext()
self.append(e)
需要注意的是linked list的性质就和list完全不一样了,我们回顾一下,list的访问元素时间都是O(1),中间插入元素为O(k)[k为插入位置后面有的元素数],而linked元素的位置由于是相对的,访问元素需要从first开始依次查找,故时间为O(k)[k为寻找元素前面的元素个数],插入元素则比较简单,改变下两个next指向就行了,所以为O(1),好吧,不开玩笑了,其实不是这样的,插入元素前需要先从头开始找到插入元素前的节点,而此为O(k),是更高阶,所有还是为O(k),好吧,其实上面两个都对,o(1)情况是若linked list无序时,直接加到最后,O(k)是若是有序的,则需要从头开始比较比它小的k个数后再放入。
python 下的数据结构与算法---4:线形数据结构,栈,队列,双端队列,列表的更多相关文章
- 《算法实战策略》-chaper19-队列、栈和双端队列
对于计算机专业的学生来说,他们一定会很熟悉一句话:程序设计 = 算法 + 数据结构.而根据笔者的理解,所谓程序设计其实就是为了编程解决实际问题,所谓算法是一种解决问题某种思维的方法,但是思维需要得到编 ...
- 用python实现栈/队列/双端队列/链表
栈是元素的有序集合,添加操作与移除操作都发生在其顶端,先进后出栈操作:创建空栈,增删(顶端),查(顶端元素,元素个数,是否为空)应用:将十进制数转换成任意进制数 class Stack: # 用列表创 ...
- 《Java数据结构与算法》笔记-CH5-链表-3双端链表
/** * 双端链表的实现 */ class LinkA { public long dData; public LinkA next; public LinkA(long d) { dData = ...
- 用Python实现的数据结构与算法:双端队列
一.概述 双端队列(deque,全名double-ended queue)是一种具有队列和栈性质的线性数据结构.双端队列也拥有两端:队首(front).队尾(rear),但与队列不同的是,插入操作在两 ...
- Python实现的数据结构与算法之双端队列详解
一.概述 双端队列(deque,全名double-ended queue)是一种具有队列和栈性质的线性数据结构.双端队列也拥有两端:队首(front).队尾(rear),但与队列不同的是,插入操作在两 ...
- 重读《学习JavaScript数据结构与算法-第三版》- 第5章 队列
定场诗 马瘦毛长蹄子肥,儿子偷爹不算贼,瞎大爷娶个瞎大奶奶,老两口过了多半辈,谁也没看见谁! 前言 本章为重读<学习JavaScript数据结构与算法-第三版>的系列文章,主要讲述队列数据 ...
- python基础教程_学习笔记19:标准库:一些最爱——集合、堆和双端队列
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/signjing/article/details/36201499 标准库:一些最爱 集合.堆和双端队 ...
- JavaScript 数据结构与算法2(队列和双端队列)
学习数据结构的 git 代码地址: https://gitee.com/zhangning187/js-data-structure-study 1.队列和双端队列 队列和栈非常类似,但是使用了与 后 ...
- 自己动手实现java数据结构(四)双端队列
1.双端队列介绍 在介绍双端队列之前,我们需要先介绍队列的概念.和栈相对应,在许多算法设计中,需要一种"先进先出(First Input First Output)"的数据结构,因 ...
随机推荐
- js回网页顶部
<!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type" content ...
- C++ template随笔
话题从重用开始说起: 最基本的重用,重用一个方法,被重用的逻辑被抽取封装成为方法,之后我们把方法当成一种工具来使用(处理数据,输入输出,或者改变状态). 来到了面向对象的时代,如果这个方法出现父类上面 ...
- HTML5 初始文档声明
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title&g ...
- 转 jQuery(图片、相册)插件代码实例
jQuery想必大部分前端er都知道甚至很熟悉了,网上有数以万计的优秀的jQuery插件以及教程,今天收集了一些关于图片.相册的jQuery插件代码,希望会对你有所帮助. 1. 3D Gallery ...
- 实现单实例多线程安全API问题
前阵子写静态lib导出单实例多线程安全API时,出现了CRITICAL_SECTION初始化太晚的问题,之后查看了错误的资料,引导向了错误的理解,以至于今天凌晨看到另一份代码,也不多想的以为singl ...
- python爬虫程序
http://blog.csdn.net/pleasecallmewhy/article/details/8922826 此人的博客关于python爬虫程序分析得很好!
- .SO 出现 undefined reference
查看本SO文件依赖哪些其他的SO文件: readelf -d ldd undefined reference 涉及的问题是 主程序及静态库不能定位地址 undefined symbol 说的问题是动 ...
- 常用排序算法之——选择排序(C语言+VC6.0平台)
选择排序是另一种经典排序算法,核心思想是:在一趟找最小(大)数的过程中,先假设待排数据中的第一个数据即为最小(大)数据,然后循环将其他数据与该数据比较,每次比较时若小于该数据则让新数据成为最小(大)数 ...
- d023: 各位数字之和
内容: 求输入的一个整数的各位数字之和 输入说明: 一行一个整数 输出说明: 一个整数 输入样例: 2147483646 输出样例 : 45 #include <stdio.h> int ...
- Entity Framework with MySQL 学习笔记一(关系整理版)
1-1 设置 //DataAnnotation 1-1 | 1-0 table //SQLtable : member , columns : memberId, name //SQL basic l ...