第10章《基本数据结构》:栈、队列、双向链表,python实现

栈和队列

栈和队列都是动态集合,栈(stack)实现的是一种后进先出策略,而队列实现的是一种先进先出策略

  • :栈上的insert操作称为压入(push),而无元素的delete操作称为弹出(pop),如下图所示,可以用一个数组 S [ 1.. n ] S[1..n] S[1..n]来实现一个最多容纳 n n n个元素的栈,该数组有一个属性 S . t o p S.top S.top,指向最新插入元素,栈中包含的元素为 S [ 1.. S . t o p ] S[1..S.top] S[1..S.top],其中 S [ 1 ] S[1] S[1]是栈底元素,而 S [ S . t o p ] S[S.top] S[S.top]是栈顶元素
    在这里插入图片描述
    S . t o p = 0 S.top=0 S.top=0时,不包含任何元素,即栈是空的,对一个空栈进行弹出操作时,则称栈下溢,这通常是一个错误,如果 S . t o p S.top S.top超过了 n n n,则称栈上溢
    python实现栈的基本操作如下:
#栈的基本操作
class Stack(object):
	#栈初始化为空
	def __init__(self):
		self.stack = []
	def isempty(self):
		return len(self.stack)==0
	#入栈
	def push(self, item):
		self.stack.append(item)
	#出栈
	def pop(self):
		return self.stack.pop()
	def size(self):
		return len(self.stack)
  • 队列:队列上的insert操作称为入队,delete操作称为出队,队列有队头(head)和队尾(tail),当 Q . h e a d = Q . t a i l Q.head=Q.tail Q.head=Q.tail时,队列为空,当 Q . h e a d = Q . t a i l + 1 Q.head=Q.tail+1 Q.head=Q.tail+1时,队列是满的。如下图所示, Q [ 1..12 ] Q[1..12] Q[1..12]实现队列的一种方式,
    在这里插入图片描述
    其中(a)队列包含5个元素,位于 Q [ 7..11 ] Q[7..11] Q[7..11],(b)中依次入队17,3,5元素,(c)中出队元素15
    python实现队列基本操作如下:

#队列的基本操作
class Queue(object):
	def __init__(self):
		self.queue = []
	def isempty(self):
		return len(self.queue)==0
	#入队列
	def enqueue(self,item):
		self.queue.insert(0,item)
	#出队列
	def dequeue(self):
		self.queue.pop()
	def size(self):
		return len(self.queue)

链表

链表是一种这样的数据结构,其中各对象按照线性顺序排列,数组的线性顺序是由数组下标决定的,然而与数组不同的是,链表的顺序是由各个对象里的指针决定的。

  • 双向链表:每个元素都是一个对象,每个元素有一个关键字key和两个指针: n e x t next next p r e v prev prev,设 x x x为链表的一个元素, x . n e x t x.next x.next指向它在链表的后继元素, x . p r e v x.prev x.prev则指向它的前驱元素, x . p r e = N I L x.pre=NIL x.pre=NIL,则元素 x x x没有前驱,即链表的头(head),如果 x . n e x t = N I L x.next=NIL x.next=NIL,则元素 x x x没有后继,是链表的最后一个元素,即链表的尾(tail)
    在这里插入图片描述
    链表可以有多种形式,它可以是单链接的或者多链接的,可以是已排序的或者未排序的,可以是循环的或非循环的。
    python实现双向链表的基本操作:
# -*-coding:utf8 -*-
import sys

#定义节点
class Node(object):
	def __init__(self, key):
		self.key = key
		self.prev = None
		self.next = None
#定义双向链表
class DoubleList(object):
	def __init__(self):
		#链表头
		self.head = Node(None)
		#链表长
		self.length = 0
	
	#判断链表是否为空
	def isEmpty(self):
		if self.length==0:
			return True
		return False

	#遍历链表
	def traversal(self):
		if self.length == 0:
			return []
		#定义游标
		cur = self.head
		keys = list()
		for i in range(self.length):
			keys.append(cur.next.key)
			cur = cur.next
		return keys

	#插入链表头
	def insert_head(self, key):
		#构造新节点
		new_node = Node(key)
		#插入到表头 O(1)
		new_node.next = self.head.next
		new_node.prev = self.head
		self.head.next = new_node
		#链表长度加1
		self.length+=1

	#插入位置i
	def insert_pos(self, pos, key):
		#判断pos的有效性
		if isinstance(pos,int):
			if pos < 0 or pos>self.length :
				insert_head(key)
			else:
				new_code = Node(key)
				cur = self.head
				for i in range(self.length):
					if i==pos:
						# 设置新节点prev和next指向
						new_node.prev = cur
						new_node.next = cur.next
						# 更新指向新节点的节点
						cur.next = new_code
						new_code.next.prev = new_code
						# 链表长度更新
						self.length+=1
					else:
						cur = cur.next
		else:
			print("pos位置无效")

	#删除元素
	def delete(self, key):
		if self.isEmpty():
			print("list is empty")
		else:
			cur = self.head
			for i in range(self.length):
				if cur.next.key == key:
					if cur.next.next is None:
						#尾部节点删除
						cur.next = None
					else:
						#中间节点
						cur.next = cur.next.next
						cur.next.prev = cur
					#更新链表长度
					self.length-=1
				else:
					cur = cur.next
	#链表的搜索
	def search(self, key):
		cur = self.head
		for i in range(self.length):
			if cur.key != key:
				cur = cur.next
		return cur

if __name__ =="__main__":
	example = DoubleList()
	#插入元素
	for i in range(8):
		example.insert_head(i)
	#遍历
	print(example.traversal())
	#链表的长度
	print(example.length)
	#删除
	example.delete(3)
	print(example.traversal())
	print(example.length)
	#搜索
	x = example.search(4)
	print(x.key)

有根树的表示

  • 二叉树:树的节点用对象表示,与链表类似,在二叉树中,如下图所示,属性 p p p l e f t left left r i g h t right right,存放指向父节点,左孩子和右孩子的指针,如果 x . p = N I L x.p=NIL x.p=NIL,则 x x x是根节点,如果节点 x x x没有左孩子,则 x . l e f t = N I L x.left=NIL x.left=NIL,右孩子情况类似,属性 T . r o o t T.root T.root指向整颗树 T T T的根节点,如果 T . r o o t = N I L T.root=NIL T.root=NIL,则该树为空。
    在这里插入图片描述

  • 分支无限制的有根树:二叉树的表示方法可以推广到每个节点的孩子树至多为常数 k k k的任意类型树,只需要 l e f t left left r i g h t right right属性用 c h i l d 1 , c h i l d 2 , . . . , c h i l d k child_1{,}child_2{,}{...,}child_k child1child2...childk代替,但当孩子节点无限制时,这种方法就失效了,所幸的是,有一个巧妙的方法可以用来表示孩子数任意的树,该方法对任意 n n n个节点的有根树,只需要 O ( n ) O(n) O(n)的存储空间,这种左孩子右兄弟表示方法( l e f t − c h i l d , r i g h t − s i b l i n g left-child,right-sibling leftchildrightsibling)如下图所示,每个节点都包含父节点 T T T,每个节点不是包含指向每个孩子的指针,而是只有两个指针:1. x x x.left-child指向节点 x x x最左边的孩子节点;2. x x x.right-sibling指向 x x x右侧相邻的兄弟节点。如果节点 x x x没有孩子节点,则 x x x.left-child= N I L NIL NIL,如果节点 x x x是其父节点的最右孩子,则 x x x.right-sibling= N I L NIL NIL
    在这里插入图片描述
    T T T的左孩子右兄弟表示法,每个节点都 x x x都有属性 x . p x.p x.p(上), x x x.left-child(左下), x x x.right-sibling(右下),关键字 k e y key key在图中未显示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值