单链表类的实现

一个普通的单链表(一个指针域),对于其最重要的就是单链表的头指针,通过头指针可以确定单链表的一些属性,如:是不是空的,通过头指针进行遍历等。
我们用python做一个单链表的类实现,要求可以建立一个空的单链表,还要能够实现一些单链表的基本操作,如判断是不是空的,头部尾部插入,删除,遍历等
首先就是定于一个链表节点的类:

class LNode:
	def __init(self, elem, next = None):
		self.elem = elem
		self.next_ = next
# 定义一个空的错误类,必须继承自基础的错误类
class LListValueError(ValueError):
	pass
	

接下来建立链表的类:

class LList:
	def __init__(self):
		self._head = None
		# 那么初始化链表类就是建立了一个空链表
	# 首先是一个判断空的方法
	def is_empty(self):
		return self._head == None
	# 接下来用于在头部插入一个节点
	def prepend(self, elem):
		self._head = LNode(elem, self._head)
		# 这是最简单的实现方法
	# 一个头部删除的方法
	# 注意删除,我们不能删除一个空链表,那么就需要使用定义的错误类
	def pop_first(self):
		if not self._head:
			raise LListValueError(“wrong”)
		e = self._head.elem
		self._head = self._head.next
		return e
		# 直接将头指针指向下一个节点,抛弃原头节点,python会自动回收
		# 其储存空间的
	# 接下来是尾部插入
	def append(self, elem):
		p = self._head
		while p:
			if not p.next_:
				p.next_ = LNode(elem)
				return
			p = p.next
		self._head = LNode(elem)
		# 这里有两种情况,一种是空表,这是直接等于就可以了
		# 其他的遍历到最后一个元素,然后将他的next指针指向这个新建的元素
		# 这里有个变量p,我们称之为扫描指针。
	# 对于尾部删除,有三种情况:空表,一个元素,两个及以上的元素
	 def pop_last(self):
	 	if not self._head:
	 		raise LListValueError("wrong")
	 	if not self._head.next:
	 		self._head = None
	 	p = self._head
	 	while p.next.next:
	 		p = p.next
	 	e = p.next.elem
	 	p.next = None
	 	return e
	# 最后关于表的遍历问题,我们对于表的遍历问题
	# 对于这种汇集对象来说,对其中的各个对象进行一些操作是很常见的,
	# 我们除了可以从头指针顺着找下去之外,还有一些是对特定元素进行的操作
	# 主要实现后者
	def for_each(self, operate):
		p = self._head
		while p:
			operate(p.elem)
			p = p.next
	# 其实还有一个就是关于python迭代器的,python的主要迭代工具就是迭代器
	# 用yield关键字生成一个生成器函数是一个很好的选择
	def elements(self):
		p = self._head
		while p:
			yield p.elem
			p = p.next

这就是一个链表类的实现。

如果深入理解链表的实现的话,可以看出self._head是头节点,但不是第一个节点,它本身是一个只包含指针域的链表对象,而这个指针就是指向链表的第一个节点。
对于更复杂的链表对象来说,我们还可以存储链表的长度,链表的尾指针等,这就需要为链表对象设计一个数据结构(一个类)
`
我在网上盗了一张图,用以说明单链表的结构

由图可以看出,first就是头指针,它不是一个节点,而是存在有第一个节点引用的“结构”吧!
所以我们叫first为链表对象,其实它不止可以保存第一个节点的引用,还以保存链表的长度,尾节点的引用或者都包含。如果我们需要有链表的长度的话,可以定义一个链表对象的类

class listObj:
	def __init__(self):
		self.node_num = 0
		self.head = None

这样我们手动加入节点数目的代码就行了
完整代码

循环链表本质上只是列表对象的结构不一样,

class cirListObj:
	def __init__(self):
		self.head = None
		self.nodeNum = 0
		self.rear = Node

至于双向链表呢,只是节点的结构不一样:

class douLNode:
	def __init__(self, elem, prev = None, next = None):
		self.prev = prev
		self.elem = elem
		self.next = next

上面两种的具体实现,后面!
参考《数据结构与算法 python语言的实现》,强推这本书!!!

面向对象程序设计课程作业 1. 请创建一个数据型为T的链表模板List,实现以下成员函数: 1) 默认构造函数List(),将该链表初始化为一个空链表(10分) 2) 拷贝构造函数List(const List& list),根据一个给定的链表构造当前链表(10分) 3) 析构函数~List(),释放链表中的所有节点(10分) 4) Push_back(T e)函数,往链表最末尾插入一个元素为e的节点(10分) 5) operator<<()友元函数,将链表的所有元素按顺序输出(10分) 6) operator=()函数,实现两个链表的赋值操作(10分) 7) operator+()函数,实现两个链表的连接,A=B+C(10分) 2. 请编写main函数,测试该模板的正确性: 1) 用List模板定义一个List型的模板对象int_listB,从键盘读入m个整数,调用Push_back函数将这m个整数依次插入到该链表中;(4分) 2) 用List模板定义一个List型的模板对象int_listC,从键盘读入n个整数,调用Push_back函数将这n个整数依次插入到该链表中;(4分) 3) 用List模板定义一个List型的模板对象int_listA,调用List的成员函数实现A = B + C;(4分) 4) 用cout直接输出int_listA的所有元素(3分) 5) 用List模板定义List型的模板对象double_listA, double_listB, double_listC,重复上述操作。(15分) 3. 输入输出样例: 1) 输入样例 4 12 23 34 45 3 56 67 78 3 1.2 2.3 3.4 4 4.5 5.6 6.7 7.8 2) 输出样例 12 23 34 45 56 67 78 1.2 2.3 3.4 4.5 5.6 6.7 7.8
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值