文章目录
在程序里,经常需要将一组(通常是同为某个类型的)数据元素作为整体管理和使用,需要创建这种元素组,用变量记录它们,传进传出函数等。在有些情况下,可能需要把这样一组元素看成一个序列,用元素在序列里的位置和顺序,表示实际应用中的某种有意义的信息,或者表示数据之间的某种关系。
线性表(简称表)就是这样一组元素(的序列)的抽象。一个线性表是某类元素的一个集合,还记录着元素之间的一种顺序关系。
线性表的概念和表抽象数据类型
表的概念和性质
考虑一个(有穷或无穷的)基本元素集合
E
E
E,集合
E
E
E中的元素可能都是某个类型的数据对象。
集合
E
E
E上的一个线性表就是
E
E
E中一组有穷个元素排成的序列
L
=
(
e
0
,
e
1
,
.
.
.
,
e
n
−
1
)
L=(e_{0},e_{1},...,e_{n-1})
L=(e0,e1,...,en−1).
一个表中包含的元素的个数称为这个表的长度。显然,空表的长度为0。
表元素之间存在一个基本关系,称为下一个关系。下一个关系是一种顺序关系,即线性关系,线性表是一种线性结构。
表抽象数据类型
一个线性表数据结构应该提供哪些操作。
1.作为抽象类型的线性表是一组数据对象的集合,应该提供创建线性表对象的操作。
2.程序中可能需要检查一个表,获取它的各方面信息。例如,可能需要判断一个表是否为空,考察其中的元素个数(求得表的长度),检查一个表里是否存在某个特定数据对象等。
3.需要动态改变表的内容,包括加入新元素或删除已有元素。
4.涉及对表中每一个元素进行的操作。
表抽象数据类型:一个表中一些有用的操作:
ADT List: # 一个表抽象数据类型
List(self) # 表构造操作,创建一个新表
is_empty(self) # 判断是否为一个空表
len(self) # 获得self的长度
prepend(self, elem) # 将元素elem加入表中作为第一个元素
append(self, elem) # 将元素elem加入表中作为最后一个元素
insert(self, elem, i) # 将元素elem加入表中作为第i个元素,其他元素的顺序不变
线性表的实现:基本考虑
计算机内存
各种重要操作的效率
两种:顺序表和连接表
顺序表的实现
python中的list和tuple就采用了顺序表的实现技术。
顺序结构(技术)是组织一组元素的最重要方式。在顺序表结构中,直接采用顺序结构实现线性表,这种结构(技术)也是许多其他数据结构的实现基础。
采用顺序表结构实现线性表:
1.最重要特点(优势)是O(1)时间的定位元素访问。很多简单操作的效率也比较高。
2.这里最重要的麻烦是加入/删除等操作的效率问题。这类操作改变表中元素序列的结构,是典型的变动操作。由于元素在顺序表的存储区里连续排列,加入/删除操作有可能要移动很多元素,操作代价高。
3.只有特殊的尾端插人/删除操作具有O(1)时间复杂度。但插人操作复杂度还受到元素存储区固定大小的限制。通过适当的(加倍)存储区扩充策略,一系列尾端插人可以达到O(1)的平均复杂度。
顺序表的优点和缺点都在于其元素存储的集中方式和连续性。从缺点看,这样的表结构不够灵活,不容易调整和变化。如果在一个表的使用中需要经常修改结构,用顺序表去实现就不太方便,反复操作的代价可能很高。
还有一个问题也值得提出:如果程序里需要巨大的线性表,采用顺序表实现就需要巨大块的连续存储空间,这也可能造成存储管理方面的困难。
链接表
线性表的基本需要和链接表
线性表的基本需要:
1.能够找到表中的首元素;
2.从表里的任一元素出发,可以找到它之后的下一个元素。
采用链接技术实现的线性表称为链接表或者链表。
基本思想:
1.把表中的元素分别存储在一批独立的存储块(称为表的结点)里;
2.保证从组成表结构中的任一个结点可找到与其相关的下一个结点;
3.在前一个结点里用链接的方式显式地记录与下一个结点之间的关联。
单链表
单链表的结点是一个二元组,元素域和链接域
元素域elem保存着作为表元素的数据项,链接域next里保存同下一个表里的下一个结点的标识。
掌握一个单链表,只需要用一个变量保存着这个表的首结点的标识。这个变量称为表头变量或表头指针。
总结:
一个单链表由一些具体的表结点构成;
每个结点是一个对象,有自己的标识或链接;
结点之间通过结点链接建立起单向的顺序联系。
基本链表操作
创建空链表
删除链表
判断表是否为空
判断表是否满
加入元素
表首端插入
一般情况的元素插入
删除元素
删除表首元素
一般情况的元素删除
扫描、定位和遍历
求表的长度
# 定义一个简单的表结点类
class LNode:
def __init__(self, elem, next_=None):
"""初始化,给两个域赋值"""
self.elem = elem
self.next = next_
def __repr__(self):
'''
用来定义Node的字符输出,
print为输出elem
'''
return str(self.elem)
llist1 = LNode(1) # 表头
# 创建链表
p = llist1
for i in range(2, 11):
p.next = LNode(i)
p = p.next
# 打印元素
p = llist1
while p is not None:
print(p.__repr__())
p = p.next
1
2
3
4
5
6
7
8
9
10
自定义异常
class LinkedListUnderflow(ValueError):
pass
LList类的定义,初始化函数和简单操作
# 定义一个简单的表结点类
class LNode:
def __init__(self, elem, next_=None):
"""初始化,给两个域赋值"""
self.elem = elem
self.next = next_
def __repr__(self):
'''
用来定义Node的字符输出,
print为输出elem
'''
return str(self.elem)
class LinkedListUnderflow(ValueError):
pass
class LList:
def __init__(self):
"""初始化,建立的是一个空表"""
self._head = None
def is_empty(self):
"""判断是一个空表"""
return self._head is None
def prepend(self, elem):
"""表头插入数据"""
self._head = LNode(elem, self._head)
def pop(self):
"""删除表头结点,并返回这个结点里的数据"""
if self._head is None: # 无结点,引发异常
raise LinkedListUnderflow("in pop")
e = self._head.elem
self._head = self._head.next
return e
def append(self, elem):
"""链表最后插入元素"""
if self._head is None:
self._head = LNode(elem)
return
p = self._head
while p.next is not None:
p = p.next
p.next = LNode(elem)
def pop_last(self):
"""删除链表最后一个元素"""
if self._head is None: # 空表
raise LinkedListUnderflow("in pop_last")
p = self._head
if p.next is None: # 只有一个元素
e = p.elem
self._head = None
return e
while p.next.next is not None:
p = p.next
e = p.next.elem
p.next = None
return e
def find(self, pred):
"""找到满足给定条件的表元素,参数提供一个判断谓词"""
p = self._head
while p is not None:
if pred(p.elem):
return p.elem
p = p.next
def printall(self):
p = self._head
while p is not None:
print(p.elem, end='')
if p.next is not None:
print(' ', end='')
p = p.next
print('')
def for_each(self, proc):
"""遍历,参数:给定的操作"""
p = self._head
while p is not None:
proc(p.elem)
p = p.next
def elements(self):
"""定义迭代器"""
p = self._head
while p is not None:
yield p.elem
p = p.next
def filter(self, pred):
"""筛选生成器,参数pred是谓词参数"""
p = self._head
while p is not None:
if pred(p.elem):
yield p.elem
p = p.next
mlist1 = LList()
for i in range(10):
mlist1.prepend(i)
for i in range(11, 20):
mlist1.append(i)
mlist1.printall()
mlist1.for_each(print)
for x in mlist1.elements():
print(x)
9 8 7 6 5 4 3 2 1 0 11 12 13 14 15 16 17 18 19
9
8
7
6
5
4
3
2
1
0
11
12
13
14
15
16
17
18
19
9
8
7
6
5
4
3
2
1
0
11
12
13
14
15
16
17
18
19