第3章 线性表

该部分为学习笔记,具体内容详见:《数据结构(Python语言描述)》一书

第一节 线性表的基本概念

线性表简称表,是由 n 个数据元素构成的有限序列,其中 n 称为线性表的表长。线性表具有以下特点:

  • 有穷性:线性表中的元素个数是有限的。
  • 同构性:一般来说,线性表中的所有元素具有相同的性质,即具有相同的类型。如果元素的性质不同,通常不具有实际应用意义。
  • 不同类型元素构成的线性表,例如一个整数线性表和一个图书清单,虽然应用场合不同,但其元素之间的逻辑关系和基本操作是相同的。

第二节 线性表的抽象数据类型

抽象数据类型从数据结构的逻辑结构及可对其进行基本操作两个方面进行定义。从定义的操作来看,线性表具有以下特性。

  • 线性表是动态的结构,可以进行元素的插入或删除,长度可以变化。
  • 线性表的插入、删除、读/写等主要操作基于位序进行。

第三节 线性表的顺序存储及实现

一、线性表顺序存储的基本方法

线性表的顺序存储方案是将表中的所有元素按照逻辑顺序一次存储在一块连续的存储空间中。线性表的顺序存储结构简称顺序表,可分为两类:元素内置的顺序表和元素外置的顺序表。

  1. 元素内置的顺序表
  2. 元素外置的顺序表

二、Python 列表的内部实现

Python 列表是一种基于元素外置存储的顺序表。一个列表对象包含引用计数(ob_refcnt)、类型(ob_type)、列表所能容纳的元素个数(allocated)、变长对象的当前长度(ob_size)以及列表元素容器的首指针(ob_item)等信息。列表元素容器是一块连续的内存块,依次存储 只想列表中各个数据元素的指针,因此列表元素容器是元素外置的顺序结构。因为每个列表元素也是一个包含类型等信息的完整结构,所以一个 Python 列表中各个元素的类型可以不同。

import sys
lst = []
empty_size = b = sys.getsizeof(lst)
count = 0
print("列表长度 %4d, 总占用字节数 %4d" % (0, b))
for k in range(500):
	lst.append(None)
	a = len(lst)
	old_b = b
	b = sys.getsizeof(lst)
	if b != old_b:
		print("列表长度 %4d, 总占用字节数 %4d,"
			  " 表元素容器大小 % 4d, 增加字节数: % 4d")
			  % (a, b, (b - empty_size) / 8, (b - old_b) / 8))

三、基于 Python 列表的实现

from AbstracList import AbstractList
class PythonList(AbstractList):
	def __init__(self):
		self._entry = []
	
	def __len__(self):
		return len(self._entry)

	def empty(self):
		return not self._entry

	def clear(self):
		self._entry = []

	def insert(self, i, item):
		self._entry.insert(i, item)

	def remove(self, i):
		self._entry.pop(i)

	def retrieve(self, i):
		return self._entry[i]

	def replace(self, i, item):
		self._entry[i] = item

	def contains(self, item):
		return item in self._entry

	def traverse(self):
		print(self._entry)

四、基于底层 C数组的实现

  1. 初始化空表的方法
def __init__(self, cap = 0):
	super().__init__()
	self._cur_len = 0
	selef._capacity = cap
	self._entry = self._make_array(self._capacity)
  1. 生成一个容量固定的底层C数组
def _make_array(self, cap):
	return (cap * ctypes.py_object)()
  1. 判别线性表是否为空
def empty(self):
	return self._cur_len == 0
  1. 求线性表的长度
def empty(self):
	return self._cur_len
  1. 清空线性表
def clear(self):
	self._capacity = 0
	self._cur_len = 0
  1. 将元素 item 添加到线性表的尾部
def append(self, item):
	if self._cur_len == self._capacity:
		if self.capacity == 0:
			cap = 4
		else:
			cap = 2 * self. _capacity
		self._resize(cap)
	self._entry[self._cur_len] = item
	self._cur_len += 1
  1. 数组的扩容
def _resize(self, cap):
	temp = self._make_array(cap)
	for k in range(self._cur_len):
		temp[k] = self._entry[k]
	del self._entry
	self._entry = temp
	self.capacity = cap
  1. 将元素 item 插入表的 i 号位置
def insert(self, i, item):
	if not 0 <= i <= self._cur_len:
		raise IndexError("插入位置不合法")
	if self._cur_len == self._capacity:
		if self._capacity == 0:
			cap = 4
		else:
			cap = 2 * self._capacity
		self._resize(cap)
	for j in range(self._cur_len, i, -1):
		self._entry[j] = self._entry[j - 1]
	self._entry[i] = item
	self._cur_len += 1
  1. 删除 i 号位置的元素
def remove(self, i, item):
	if self.empty():
		raise Exception("underflow")
	if not 0 <= i < self._cur_len:
		raise IndexError("删除位置不合法")
	item = self._entry[i]
	for j in range(i, self._cur_len - 1):
		self._entry[j] = self._entry[j + 1]
	self._cur_len -= 1
	return item
  1. 读取 i 号元素
def retrieve(self, i):
	if not 0 <= i < self._cur_len:
		raise IndexError("元素读取位置不合法")
	return self._entry[i]
  1. 将 item 值写入表的 i 号位置
def replace(self, i, item):
	if not 0 <= i < self._cur_len:
		raise IndexError("元素写入位置不合法")
	self._entry[i] = item
  1. 判断指定元素 item 在表中是否存在
def contains(self, item):
	for i in range(self._cur_len):
		if self._entry[i] == item:
			return True
	return False
  1. 将线性表转换成字符串
def __str__(self):
	elements = ''.join(str(self._entry[c]) for c in range(self._cur_len))
	return elements

第四节 线性表的链式存储及实现

在链式结构中,元素在内存中的映像称为结点,结点包含元素值和指针域两大部分,其中,指针域用于记录其后继结点或前驱结点的地址。可见,链式结构通过显式的指针域来表明元素的前驱、后继关系。线性表的链式实现结构简称为链表,根据结点中指针域的数目及尾部结点指针的定义,链表可以分为单链表、双向链表、循环链表等。最常见的链表形式是单链表。

一、单链表

单链表的每个结点包含两个域,其中 entry 域存储元素, next 域存储后继结点的指针。为使操作更简单、方便,通常在单链表首结点前附加一个表头结点(简称头结点),即为带头结点的单链表

  1. 定义结点类
class Node:
	def __init__(self, data, next = None):
		self.entry = data
		self.next = next
  1. Python 语言实现一个带头结点的单链表
from AbstractList import AbstractList
from Node import Node
class LinkedList(AbstractList):
	def __init__(self):
	def empty(self):
	def __len__(self):
	def clear(self):
	def insert(self, i, item):
	def remove(self, i):
	def retrieve(self, i):
	def replace(self, i, item):
	def contains(self, item):
	def traverse(self):
	def get_head(self):
  1. 初始化空表的方法
def __init__(self):
	self._head = Node(None)
  1. 判别线性表是否为空
def empty(self):
	return self._head.next is None
  1. 求线性表的长度
def __len_