线性表: Python语言描述

目录

1. 单链表

      1.1 普通单链表(分析)

【表结点类】

【基本链表操作】

【加入元素】

【删除元素】

【扫描、定位和遍历】

【求表的长度】

【后端操作】

【查找元素】

【打印所有元素信息】

      1.2 普通单链表(实现)

      1.3 带有尾结点引用的单链表

【初始化和变动操作】

      1.4 循环单链表

2. 双链表

【结点操作】

【双链表类】

3. 两个链表操作

【链表反转】

【链表排序】


1. 单链表

      1.1 普通单链表(分析)

【表结点类】

元素域(elem) & 链接域(next)

class LNode(object):
      """结点"""
  
      def __init__(self, elem, next_=None):  #使用next_是为了避免与标准函数next重名
          self.elem = elem
          self.next = next_                  #初始设置下一节点为空

【基本链表操作】

创建空链表:把表头指针设置为空链接,Python中用None表示空.

删除链表:把表头指针赋值为None.

判断表是否为空:检查表头变量的值是否为None.

判断表是否满:当存储空间足够时,链表不会满.

【加入元素】

表首端插入:

1)创建一个新结点并存入数据;

2)把原链表首结点的链接存入新结点的链接域next;

3)修改表头指针,使之指向新结点.

q = LNode('data')    #创建新结点
q.next = head        #连接新结点与原链表
head = q             #修改表头指针

一般情况插入:

1)创建一个新结点并存入数据;

2)将pre所指结点next域的值存入新结点的链接域next;

3)修改pre的next域,使之指向新结点.

q = LNode('data')          #创建新结点
q.next = pre.next          #新结点与原表后段连接
pre.next = q               #原表前段与新结点连接

【删除元素】

以下均假设表非空.

删除表首元素:

直接将表头指针指向表中第二个结点.

head = head.next

一般情况的元素删除:

找到被删除元素所在结点的前一结点,将它的next域指向被删除结点的下一结点.

pre.next = pre.next.next

【扫描、定位和遍历】

基本扫描模式:

p = head
while p is not None and '其他条件':
    '相关操作'
    p = p.next

按下标定位:

确定第 i 个元素所在结点,注意,链表首结点的下标为0.

p = head
while p is not None and i > 0 :
    i -= 1
    p = p.next

循环结束时,要么没有找到(p指向None),要么找到,此时检查p的值是否为None即可.

按元素定位:

pred为相应条件的谓词.

p = head
while p is not None and not pred(p.elem):
    p = p.next

【求表的长度】

def length(head):
    p = head
    n = 0
    while p is not None:
        n += 1
        p = p.next
    return n

【后端操作】

后端操作必须先找到链表的最后一个结点.

后端插入元素:

这里需要区分两种情况:

1)原表为空,引用新结点的应该是表头指针的next域;

2)原表不为空,引用新结点的应该是已有最后结点的next域.

由于插入的元素位于后端,其结点的next域为默认的None,无需再指明.

def append(self, elem):
    if self._head is None:
        self._head = LNode(elem)
        return
    p = self._head
    while p is not None:
        p = p.next
    p.next = LNode(elem)

后端删除元素:

后端操作必须先找到链表的最后一个结点,而若欲删除后端元素,则需找到它的前一个结点,即表的倒数第二个结点,也就是找到 p.next.next 为None的p.

此外,当表中只有一个元素时需要特殊处理,这是需要修改表头指针.

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('')

      1.2 普通单链表(实现)

class LList(object):
      """单链表"""

  
    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)  #elem来自于stdin,head来自于原表


    def pop_first(self):        #删除表头结点并返回其元素
        if self._head is None:  #表为空,引发异常
            raise LinkedListUnderflow("in pop")
        e = self._head.elem
        self._head = self._head.next  


    def append(self, elem):
        if self._head is None:
            self._head = LNode(elem)
            return
        p = self._head
        while p 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 length(head):
        p = head
        n = 0
        while p is not None:
            n += 1
            p = p.next
        return n

      1.3 带有尾结点引用的单链表

将表对象增加一个表尾结点引用域,只需常量时间就能找到尾结点.

此 class 以 LList 为基类.

【初始化和变动操作】

在LList1的初始化函数中,应该首先初始化LList对象的那些数据域,对此可直接对self对象调用LList类的初始化函数.现在还需要一个尾结点引用域,将它初始化为None.

def __init__(self):
    LList.__init__(self)
    self._rear = None

前端插入操作:

一般情况下的操作与LList相同,但当表为空时则不同.如果原来是空表,则新加入的第一个结点也是最后一个结点.

def prepend(self, elem):
    if self._head is None:
        self._head = LNode(elem,self._head)
        self._rear = self._head
    else:
        self._head = LNode(elem,self._head)

后端插入操作:

def append(self, elem):
    if self._head is None:
        self._head = LNode(elem,self._head)
        self._rear = self._head
    else:
        self._rear.next = LNode(elem)   #创建新结点
        self._rear = self._rear.next    #更新尾结点引用

弹出末元素操作:

删除尾结点之后还需更新 _rear.

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.next是尾结点
        p = p.next
    e = p.next.elem
    p.next = None
    self._rear = p
    return e

      1.4 循环单链表

最后一个结点的next域不用None,而是指向表的第一个结点.但仔细考虑,会发现在链表对象里记录表尾结点更合适,这样可以同时支持O(1)时间的表头/表尾插入和O(1)时间的表头删除.

class LCList:
    
    def __init__(self):
        self._rear = None
        
        
    def is_empty(self):
        return self._rear is None
    

    def prepend(self,elem):
        p = LNode(elem)
        if self._rear is None:
            p.next = p
            self._rear = p
        else:
            p.next = self._rear.next
            self._rear.next = p
            
        
    def append(self,elem):
        self.prepend(elem)
        self._rear = self._rear.next
        
        
    def pop(self):
        if self._rear is None:
            raise LinkedListUnderflow("in pop of CLList")
        p = self._rear.next
        if self._rear is p:
            self._rear = None
        else:
            self._rear.next = p.next
        return p.elem
    

    def printall(self):
        if self.is_empty():
            return
        p = self._rear.next
        while True:
            print(p.elem)
            if p is self._rear():
                break
            p = p.next

2. 双链表

【结点操作】

结点删除:

p.prev.next = p.next
p.next.prev = p.prev

结点加入:


【双链表类】

1)双链表的结点在LNode类的基础上派生,多了一个反向引用域prev.

2)首端/尾端的相同操作几乎是对称的,其中的_head与_rear对应,next与prev对应.

class DLNode(LNode):
    def __init__(self,elem,prev=None,next_=None):
        LNode.__init__(self,elem,next_)
        self.prev = prev
     
        


class DLList(LList1):
    
    def __init__(self):
        LList1.__init__(self)
        
        
    def prepend(self,elem):
        p = DLNode(elem,None,self._head)
        if self._head is None:
            self._rear = p
        else:
            p.next.prev = p
        self._head = p
        
        
    def append(self,elem):
        p = DLNode(elem,self._rear,None)
        if self._head is None:
            self._head = p
        else:
            p.prev.next = p
        self._rear = p
        
        
    def pop_first(self):
        if self._head is None:
            raise LinkedListUnderflow("in pop_first of DLList")
        e = self._head.elem
        self._head = self._head.next
        if self._head is not None:
            self._head.prev = None
        return e
    
    
    def pop_last(self):
        if self._head is None:
            raise LinkedListUnderflow("in pop_last of DLList")
        e = self._rear.elem
        self._rear = self._rear.prev
        if self._rear is None:
            self._head = None
        else:
            self._rear.next = None
        return e
        



3. 两个链表操作

【链表反转】

对于单链表而言,如果不断向一个表的首端插入结点,最早放进去的结点将在表的最后.相应的,从表的首端取下结点,最后取下的是尾结点.也就是说,从一个表的首端不断取下结点,将其加入另一个表的首端,就形成了一个反转过程.

def rev(self):
    p = None                     #创建一个新链表
    while self._head is not None:
        q = self._head           #取下首结点 
        self._head = q.next      #更新表头指针
        q.next = p               #取下的结点与新表连接
        p = q                    #新表对象更新             
    self._head = p               #反转后的表头指针

【链表排序】

基于移动元素的单链表排序:

1)大循环:扫描指针crt每次处理一个元素x并前进一步;

2)小循环:从头开始到指针位置扫过小于或等于x的元素,直到找到第一个大于x的元素;

3)做一系列“倒换”,将x放入正确位置,并将其它元素后移.

def sort_1(self):
    if self._head is None:
        return
    crt = self._head.next
    while crt is not None:
        x = crt.elem
        p = self._head
        while p is not crt and p.elem <= x:
            p = p.next
        while p is not crt:
            y = p.elem    #取出p当前元素
            p.elem = x    #将x放入当前p中
            x = y         #更新x为之前p中元素
            p = p.next    #p前进一步
        crt.elem =x       #crt元素更新为crt前一结点元素
        crt = crt.next    #crt前进一步

基于调整链接的单链表排序:

1)表头为空或表只有一个元素,自然处于有序状态,无序排序;

2)用rem记录除第一个元素之外的结点段,通过循环把这些结点逐一插入_head关联的排序段;

3)p指针用于从表头扫描到rem,直到找到第一个大于rem.elem的元素,此时p指向该元素所在结点,q指针用于指向该结点之前的那个结点,那么rem应插入q和p之间;

4)注意区分表头插入和一般插入;

5)连接好q,rem,p后,将rem前进一步.

def sort_2(self):
    p = self._head
    if p is None or p.next is None:
        return

    rem = p.next
    p.next = None
    while rem is not None:
        p = self._head
        q = None
        while p is not None and p.elem <= rem.elem:
            q = p
            p = p.next
        if q is None:       #表头插入
            self._head = rem
        else:               #一般插入
            q.next = rem    #只是将q与rem连接而未将rem与后面部分连接
        q = rem             #用q暂存已排序的rem结点
        rem = rem.next      #rem结点前进一步
        q.next = p          #更新已排序的rem结点的next域

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值