标签:记录 算法 删除 组织 根据 one 覆盖 单链表 init
目录
线性表实现的基本需要:
显然,把表元素保存在连续的存储区里,自然满足这两个需求,顺序关联是隐含的。但满足这两种需求,并不一定要连续存储元素
实现线性表的另一方式是基于链接结构,用链接显式地表示元素之间的顺序关联。基于链接技术实现的线性表称为链接表或链表
实现链接表的基本想法:
链接表有多种不同的组织方式。下面先讨论最简单的单链表,其中每个结点里记录着下一元素的结点的标识。
单链表结点的形式(链接域保存下一结点的标识)
在单链表里,与表里的 n 个元素对应的 n 个结点通过链接形成一条结点链。从表里的任一个结点都可以找到保存下一个元素的结点
要掌握一个单链表,就需要(也仅需要)掌握表的首结点,从它
表头变量:保存着链表第一个结点的标识(链接)的变量
一个具体的表由一些具体结点构成
通过判断是否空链接,可以知道是否已经到了表的结束
在实现算法时,我们并不需要关心具体的表里各结点的具体链接的值是什么(它们总保存在表结构里),只需要关心链表的逻辑结构
## 单链表操作:基本操作
考虑链接表的几个基本操作:
给单链表加入元素的一些基本情况
通过修改链接,改变表的结构
首端加入: 1) 创建一个新结点存入数据; 2) 把原链表首结点的链接存入新结点的链接域; 3) 修改表头变量使之引用新结点
尾端加入: 1) 创建一个新结点存入数据; 2) 表空时直接让表头变量引用这个新结点并结束,否则找到表尾结点; 3) 令表尾结点的链接域引用这一新结点,并将新结点的链接域设置为空链接
定位加入: 1) 找到新结点加入位置的前一结点,不存在时结束; 2) 创建新结点存入数据; 3) 修改前一结点和新结点的链接域将结点连入
删除元素,所用技术与加入元素类似
定位删除:找到要删除元素所在结点的前一结点,修改它的链接域将要求删除的结点从表中去掉
在表中查找特定位置的元素,或查找满足某些条件的元素
进行这类操作,都需要用一个(或几个)扫描变量
有些表操作比较复杂,例如表元素排序
(排序 待续)
判断空表: O(1)
加入元素(都需要加一个 T(分配) 的时间):
删除元素:
其他操作,如果需要扫描整个表或其一部分,都是 O(n) 操作。如
一类典型的表操作是扫描整个表,对表中每个元素做同样的工作(即遍历操作)。例如,输出所有的元素值,将它们累积到一个变量里等。
这种工作可以通过一个循环完成
遍历操作的复杂性应该是 O(n) * T(元素操作)
有可能改造表的表示方式,提高一些操作的效率。例如,如果工作中经常需要求表长度,可以考虑采用下面结构(加一个表头对象):
这样,在加入/删除元素时需要维护个数记录,有得有失
## 单链表的Python实现
实现链接结构,需要定义相应的类,首先是表示结点的类
下面是一个简单的结点类:
class LNode : # 只定义初始化操作
def __init__(self, elm, nxt):
self.elem = elm
self.next = nxt
简单的使用代码(Python 允许直接访问对象的普通数据域):
llist1 = LNode(1, None); pnode = llist1
for i in range(2, 11):
pnode.next = LNode(i, None)
pnode = pnode.next
pnode = llist1
while pnode is not None:
print(pnode.elem)
pnode = pnode.next
基于结点 LNode 定义一种链接表类型,为此定义一个表类
class LList:
def __init__(self):
self.head = None
def isEmpty(self):
return self.head == None
def prepend(self, elem):
self.head = LNode(elem, self.head
LList 对象只有一个 head 域,指向表中的首结点。几个操作(方法):
append 在表最后加入一个包含新元素的结点
def append(self, elem):
if self.head == None:
self.head = LNode(elem, None)
return
p = self.head
while p.next != None:
p = p.next
p.next = LNode(elem, None)
注意,这里需要区分两种情况:
首/尾端弹出元素的方法(删除操作与此类似)
def pop(self): # 首端弹出
if self.head == None:
raise ValueError
e = self.head.elem
self.head = self.head.next
return e
def poplast(self): # 尾端弹出,显然复杂性为 O(n)
if self.head == None: # empty list
raise ValueError
p = self.head
if p.next == None: # list with only one element
e = p.elem; self.head = None
return e
while p.next.next != None: # till p.next be the last node
p = p.next
e = p.next.elem; p.next = None
return e
def find(self, pred): # 在表里找到第一个满足 pred 的元素返回
p = self.head
while p != None:
if pred(p.elem):
return p.elem
p = p.next
return None
def printall(self): # 输出表中所有元素
p = self.head
while p != None:
print(p.elem)
p = p.next
单链表并非只有一种设计,可以根据需要和认识修改设计,例如
一种可能是采用下面的结构,给表对象增加一个对表尾结点的引用:
这样,在尾端加入元素,也能做到 O(1)
面向对象技术支持基于已有的类(基类)定义新类(派生类)
回到链表,我们可以基于 LList 定义(具有前述结构的)新链表类
通过继承方式定义新类
class LList1(LList) :
Python 规定,定义时不注明基类,自动以公共类 object 作为基类
前面的 LNode 和 LList 都以 object 作为基类
LList1 定义为 LList 的派生类,覆盖 LList 的一些方法
class LList1(LList):
def __init__(self):
LList.__init__(self) # 调用 LList 的初始化方法
self.rear = None
def prepend(self, elem):
self.head = LNode(elem, self.head)
if self.rear == None: # the empty list
self.rear = self.head # rear points also to the new node
def append(self, elem):
if self.head == None:
self.prepend(elem) # call prepend, do the same
else:
self.rear.next = LNode(elem, None)
self.rear = self.rear.next
首端和尾端删除方法也需要覆盖
def pop(self):
if self.head is None:
raise ValueError
e = self.head.elem
if self.rear is self.head: # list with one node
self.rear = None
self.head = self.head.next
return e
def poplast(self):
return None # to be implemented or simply use this
带尾结点记录的单链表可以很好支持前/尾端加入和首端弹出元素
[Data Structure]线性表Linear List2
标签:记录 算法 删除 组织 根据 one 覆盖 单链表 init
原文地址:https://www.cnblogs.com/HuisClos/p/10367625.html