python数据结构与算法-基本数据结构类型

学习目标

  • 了解抽象数据类型:栈stack,队列queue,双端队列deque,列表list;
  • 用python列表数据结构,实现stack/queue/dequeue抽象数据类型的构建;
  • 采用队列queue进行基本的时间模拟;

一、栈

栈是一个项的有序集合,添加和移除项都发生在同一端,这一段称为“顶”,另一端的顶部被称为“底”。我们可以将栈同类比为一摞书(如下图),先放的书在最底下,称为栈底,最后放的书在最上面,称为栈顶,同样移除书时也是先移走顶端的书。栈的数据添加和移除也遵循这一原则,我们称之为“后进先出”原则。 放入和取出的顺序相反,这一属性也称为栈的“逆转属性”。
栈

1.1 栈的抽象数据类型

  • stack()创建一个新的空栈,返回空栈;
  • push(item)在栈顶添加一个新的项;
  • pop()移除栈顶的项,并返回此项;
  • peek()返回栈顶的项,不进行任何操作;
  • isEmpty()测试栈是否为空,返回布尔值;
  • size()返回栈的项目数,返回一个整数。

二、队列

队列是一系列有顺序的元素的集合,新元素加入的一端被称为“队尾”,队列的另一端称为“队首”,队列的元素添加或移除遵循“先进先出”原则,注意和栈不同!下图是由python数据对象构成的队列:
在这里插入图片描述

2.1抽象数据类型QUEUE

  • queue()创建一个空队列对象,返回空的队列;
  • enqueue(item)将数添加到队尾;
  • dequeue()从队首移除数据项,并返回此项;
  • isEmpty()测试是否为空队列,并返回一个布尔值;
  • size()返回队列中的数据项的个数。

2.2用python实现Queue

class Queue:
	def __init__(self):
		self.items=[]

	def isEmpty(self):
		return self.items==[]

	def enqueue(self,items):
		self.items.insert(0,items)

	def dequeue(self):
		return self.items.pop()

	def size(self):
		return len(self.items)

2.3模拟算法:打印任务

以下为主要模拟过程:
1.创建一个打印任务队列,每个任务在生成时被赋予一个“时间邮戳”,队列在开始时是空的。
2.对于每一秒(打印过程的当前秒(currentSecond)
(1)是有由新的打印任务生成?如果有,把它加入打印队列,并把当前秒作为其“时间邮戳”
(2)如果打印机空闲并且有任务正在等候队列中:
1从打印列表中移除下一个打印任务并且将其交给打印机;
2从当前秒中减去“时间邮戳”值,计算得到该任务的等待时间;
3将该任务的等待时间添加到一个列表中,用于后续操作;
4基于打印的页数,求出需要多长的打印时间。
(3)如果此时打印机再工作中,对于打印机而言,就工作了一秒钟;对于打印任务而言,它离打印结束又近了一秒钟(剩余打印时间减1)
(4)如果此时打印任务已经完成,也就是剩余打印时间为0时,打印机进入空闲状态。
3.在整个模拟算法完成后,依据生成的等待时间列表中的数据,计算平均打印时间。

python实现打印任务

我们需要为描述前述的三个真实世界的对象: 打印机(Printer)、 打印任务(Task)和打印队列(PrintQueue)来自定义一些类。

  • 模拟打印机的类 Printer需要实时监测是否正在执行打印任务。如果是,则表示打印机正忙,需要的等待时间可以由当前任务的打印张数求得。同时初始构造函数还要能完成单位时间打印张数的初始化设置。
  • 方法 tick 用于减去内设任务的完成所需时间,并在一次任务结束后将打印机设为闲置。
class Printer:
	def __init__(self,ppm):
	self.pagerate = ppm
	self.currentTask = None
	self.timeRemaining = 0
	
	def tick(self):
		if self.currentTask!=None:
			self.timeRemaining = self.Remaining-1
			if self.timenRemaining<=0:
				self.currentTask=None
	
	def busy(self):
		if self.currentTask!=None:
			return True
		else:
			return False

	def startNext(self,newtask):
		self.currentTask=newtask
		self.timeRemaining = newtask.getPages()*60/self.pagerate

类Task代表一个单独的打印任务,当一个任务被创建时,随机生成器生成一个1到20之间的一个随机数代表打印的页数,我们选择了random模块中的ranrange方法。
每个打印任务还需要定义一个用于计算等待时间的对象timestamp,timestamp会记录下任务被创建和被放入打印队列时的时间,方法waitTime用于检索任务开始打印前在队列中的等待时长。

import random

class Task:
	def __init__(self,item):
		self.timestamp = time
		self.pages = random.randrange(1,21)

	def getStamp(self):
		return self.timestamp

	def getPages(self):
		return self.pages

	def waitTime(self,currenttime):
		return currenttime-self.timestamp
		

主函数simulation可以实现上述算法:

import Queue
import random
def simulation(numSeconds,pagesPerMinute):
	
	labprinter = printer(pagesPerMinute)
	printQueue = Queue()
	waitingtimes = []

	for currentSeconds in range(numSeconds):
		if newPrinteTask():
			task = Task(currentSecond)
			printerQueue.enqueue(task)
		if (not labprinter.busy()) and (not printQueue.isEmpty()):
			nexttask = printQueue.dequeue()
			waintingtimes.append(nexttask.waitTime(currentSecond))
			labprinter.starNext(nexttask)

		labprinter.tick()

三、双端队列

双端队列与队列相似,不过添加或删除数据可以从任意两端进行,它拥有栈和队列各自拥有的属性。在这里插入图片描述

3.1抽象数据类型

  • Deque()创建一个空双端队列;
  • addFront(item)在队首插入一个元素;
  • addRear(item)在队尾插入一个元素;
  • removeFront()在队首移除一个元素,并返回改元素;
  • removeRear()在队尾移除一个元素,并返回改元素;
  • isEmpty()判断双端队列是否为空,返回布尔值;
  • size ()返回双端队列中数据项的个数。

四、列表LIST

列表是一些元素的集合,每个元素拥有一个与其它元素不同的相对位置。例如列表[54,26,93,17,77,31]

4.1无序列表

我们通过构建一个链表来实现列表,以上面的列表[54,26,93,17,77,31]为例,看起来这些数被随机放置,但是通过以下将每个项目简单链接,将其明确显示出来。
在这里插入图片描述
第一个位置必须被明确指出,一旦知道第一项,那么其他项就可通过链接寻找出来,从外部只想的第一项通常被称为链表的“头”,同理,链表的最后一项需要告诉我们后面没有其他项,用None链接。

4.1.1抽象数据类型

  • list() 创建一个新的空列表。它不需要参数,而返回一个空列表。
    *add(item) 将新项添加到列表,没有返回值。假设元素不在列表中。
    *remove(item) 从列表中删除元素。需要一个参数,并会修改列表。此处假设元
    素在列表中。
    *search(item) 搜索列表中的元素。需要一个参数,并返回一个布尔值。
    *isEmpty() 判断列表是否为空。不需要参数,并返回一个布尔值。
    *size() 返回列表的元素数。不需要参数,并返回一个整数。
    *append(item) 在列表末端添加一个新的元素。它需要一个参数,没有返回值。
    假设该项目不在列表中。
    *index(item) 返回元素在列表中的位置。它需要一个参数,并返回位置索引值。
    此处假设该元素原本在列表中。
    *insert(pos,item) 在指定的位置添加一个新元素。它需要两个参数,没有返回值。
    假设该元素在列表中并不存在,并且列表有足够的长度满足参数提供的索引需要。
    *pop() 从列表末端移除一个元素并返回它。它不需要参数,返回一个元素。假
    设列表至少有一个元素。
    *pop(pos) 从指定的位置移除列表元素并返回它。它需要一个位置参数,并返回
    一个元素。假设该元素在列表中。

4.1.2节点Node

用链表实现的基本模块是节点。每个节点对象必须持有至少两条信息。首先,节点必须包含列表元素本身。我们将这称为该节点的“数据区”。此外,每个节点必须保持到下一个节
点的引用。Python 的特殊值 None 将在节点类和之后的链表类中发挥重要的作用。引用 None 意味着没有下一个节点。
所以用None来作为你初始化时对下一个节点的引用是一个好主意。在这里插入图片描述

4.2有序列表

有序列表的结构是一个数据的集合体,在集合体中,每个元素相对其他元素有一个基于元素的某些基本性质的位置。假设我们已经在列表元素中定义了一个有意义的比较大小的操作,则排序通常是升序或降序。有序列表的许多方法和无序表是一样的。

4.3链表实现算法分析

考虑一个有 n 个节点的链表, isEmpty 方法复杂度是 O(1),因为它只需要检查链表的头指针是否为 None。对于方法 size,则总需要 n 个步骤,因为除了遍历整个链表以外,没有办法知道链表的节点数。因此, size 方法的复杂度是 O(n)。无序列表的 add 方法的复杂度是 O(1),因为我们永远只需要在链表的头部简单地添加一个新的节点。但是, search、 remove 和在有序列表中的 add 方法,需要遍历。尽管在平均情况下,它们可能只需要遍历一半的节点,但这些方法的复杂度都是 O(n),因为在最糟糕的情况下
需要遍历整个链表。

方法链表复杂度有序列表复杂度
isEmpty()O(1)O(1)
size()O(n)O(n)
add()O(1)O(n)
search()O(n)O(n)
remove()O(1)O(n)
数据结构与算法Python) 一、引入概念 1-01算法引入 1-02 时间复杂度与大O表示法 1-03-最坏时间复杂度与计算规则 1-04-常见时间复杂度与大小关系 1-05-代码执行时间测量模块 1-06-Python列表类型不同操作的时间效率 1-07-Python列表与字典操作的时间复杂度 1-08-数据结构引入 二、顺序表 2-01 内存、类型本质、连续存储 recv 2-02 基本顺序表与元素外围顺序表 recv 2-03 顺序表的一体式结构与分离式结构 recv 2-04 顺序表数据区替换与扩充 recv 三、栈 3-01 栈与队列的概念 3-02 栈的实现 3-03 队列与端队列的实现 四、链表 4-01 链表的提出 4-02 单链表的ADT模型 4-03 Python中变量标识的本质 4-04 单链表及结点的定义代码 4-05 单链表的判空、长度、遍历与尾部添加结点的代码实现 4-06 单链表尾部添加和在指定位置添加 4-07 单链表查找和删除元素 4-08 单链表与顺序表的对比 4-09 单向循环链表遍历和求长度 4-10 单向循环链表添加元素 4-11 单向循环链表删除元素 4-12 单向循环链表删除元素复习及链表扩展 4-13 向链表及添加元素 4-14 向链表删除元素 五、排序与搜索 5-01 排序算法的稳定性 5-02 冒泡排序及实现 5-03 选择排序算法及实现 5-04 插入算法 5-05 插入排序 5-06 插入排序2 5-07 希尔排序 5-08 希尔排序实现 5-09 快速排序 5-10 快速排序实现1 (1) 5-10 快速排序实现1 5-11 快速排序实现2 5-12 归并排序 5-13 归并排序 代码执行流程 5-14 归并排序时间复杂度及排序算法复杂度对比 5-15 二分查找 5-16 二分查找时间复杂度 六、树和树的算法 6-01 树的概念 6-02 二叉树的概念 6-03 二叉树的广度优先遍历 6-04 二叉树的实现 6-05 二叉树的先序、中序、后序遍历 6-06 二叉树由遍历确定一棵树 ———————————————— 版权声明:本文为CSDN博主「dwf1354046363」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。 原文链接:https://blog.csdn.net/dwf1354046363/article/details/119832814
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值