Python算法与数据结构(三)------ 链表

目录

一. 链表作用和定义

1.1作用

 顺序表构建需要预习知道数据大小来申请连续的存储空间且涉及数据搬迁等操作,并不灵活,链表结构却可以充分利用计算机内存空间,实现灵活的内存动态管理。

1.2定义

链表是一种线性表,在每一个节点(数据存储单元)里存放下一个节点的位置信息(即地址)。

在这里插入图片描述

二. 单向链表

2.1定义:

单向链表也叫单链表,每个节点包含两个域,一个信息域(元素域)和一个链接域。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。
尾节点的链接域指向空

在这里插入图片描述

2.2 单链表的操作

is_empty() 链表是否为空
length() 链表长度
travel() 遍历整个链表
add(item) 链表头部添加元素
append(item) 链表尾部添加元素
insert(pos, item) 指定位置添加元素
remove(item) 删除节点
search(item)查找节点是否存在

2.3单链表节点的实现

#定义一个单链表类
class Node(object):
    #单链表的节点
    def __init__(self,item):
        #item存放数据元素
        self.item = item
        #next是下一个节点的标识
        self.next = None

2.4 单链表的头部添加元素与尾部添加元素

在这里插入图片描述

2.5 单链表在指定位置添加元素

在这里插入图片描述

2.6 删除节点

在这里插入图片描述

class Node(object):
    #单链表的节点
    def __init__(self,element):
        #item存放该节点的数据元素
        self.element = element
        #next是下一个节点的标识
        self.next = None
 
class SingleLinkList(object):
    # 单链表
    def __init__(self,node = None):
        self.__head= None #类的私有属性_head
 
    def is_empty(self):
        #链表是否为空
        return self.__head == None
 
    def length(self):
        #链表长度
        #cur游标,用来移动遍历节点
        cur = self.__head
#如果链表不为空时,self.__head其实已经就是指向一个节点了,此时cur和self.__head引用的地址相同,所以cur指向的是一个node,而node当然有.next属性了。初学者容易误以为此时的cur指向的是__head,其实这种理解有偏差,应该理解位cur指向的是第一个node,因为__head本身并不是一个实际的node而是一个指向第一个node的引用
        #count记录数量
        count = 0
        while cur != None:
            count += 1
            cur = cur.next
        return count
 
    def travel(self):
        #遍历链表
        cur = self.__head
        while cur != None:
            print(cur.element,end = "  ")
            cur = cur.next
 
    def add(self, item):
        #链表头部添加元素,其实就相当于在__head和__head指向的node中间插入一个node
        node = Node(item) #实例化这个node
        node.next = self.__head #、
        self.__head = node
 
    def append(self, item):
        #在链表尾部添加节点
        node = Node(item) #node节点
        if self.is_empty():
            self.__head = node #把头接上定义好的节点
        else:
            cur = self.__head
            while cur.next != None: #cur移动到最后
                cur = cur.next
            cur.next = node #指向节点
 
 
    def insert(self, pos, item):
        #插入元素
        node = Node(item)
        if pos <= 0:
            self.add(item)
        elif pos > (self.length() - 1):
            self.append(item)
        pre = self.__head
        count = 0
        while count < pos - 1 : #count数到pos-1的时候就要跳出循环
            count += 1
            pre = pre.next
        node.next = pre.next
        pre.next = node
 
    def remove(self,item):
        # 删除节点
        pre = None
        cur = self.head
        if cur.element == item:
            self.head = self.head.next
        else:
            while cur:
                if cur.element != item:
                    pre = cur
                    cur = cur.next
                else:
                    pre.next = cur.next
                    cur.prev = pre.next
                    break
 
if __name__ == '__main__':
    link = SingleLinkList()
    print('链表是否为空?', link.is_empty())
    print('链表长度:', link.length())
    print('添加头结点:')
    for item in range(1,7):
        link.append(item)
    link.travel()
    print('链表是否为空?', link.is_empty())
    print('链表长度:', link.length())
    

2.7 链表与顺序表的对比

虽然链表看起来复杂度更高,但链表和顺序表在插入和删除时进行的是完全不同的操作。链表主要耗时操作是遍历查找,顺序表主要耗时操作是拷贝覆盖。(数据搬迁)
操作链表顺序表
访问元素O(n)O(1)
在头部插入/删除O(1)O(1)
在尾部插入/删除O(n)O(1)
在中间插入/删除O(n)O(n)

三. 单向循环链表

3.1 定义

单链表的一个变形是单向循环链表,链表中最后一个节点的next域不再为None,而是指向链表的头节点。

在这里插入图片描述

3.2 操作

is_empty() 链表是否为空
length() 链表长度
add(item) 链表头部添加元素
append(item) 链表尾部添加元素
insert(pos, item) 指定位置添加元素
remove(item) 删除节点
search(item) 查找节点是否存在

3.3 操作实现

#单向循环链表节点
class Node(object):
    def __init__(self, item):
        self.item = item
        self.next = None
 
#单向循环链表
class SinCycLinkedlist(object):
    def __init__(self):
        self.__head = None
 
    def is_empty(self):
        return self.__head == None
 
    def length(self):
        if self.is_empty():
            return 0
        count = 1
        cur = self.__head
        while cur.next != self.__head:
            count += 1
            cur = cur.next
        return count
 
    def travel(self):
        #遍历链表                            
        if self.is_empty():
            return
        cur = self.__head
        print(cur.item)
        while cur.next != self.__head:
            cur = cur.next
            print(cur.item)
        print("")
 
    def add(self, item):  
        #头部添加元素                       
        node = Node(item)
        if self.is_empty():
            self.__head = node
            node.next = self.__head
        else:
            node.next = self.__head               # 添加的节点指向_head
            cur = self.__head                     # 移到链表尾部,将尾部节点的next指向node
            while cur.next != self.__head:
                cur = cur.next
            cur.next = node
            self.__head = node                    # head指向添加node的
 
    def append(self, item):                       # 尾部添加元素
        node = Node(item)
        if self.is_empty():
            self.__head = node
            node.next = self.__head
        else:
            cur = self.__head                     # 移到链表尾部
            while cur.next != self.__head:
                cur = cur.next
            cur.next = node                       # 将尾节点指向node
            node.next = self.__head               # 将node指向头节点_head
 
    def insert(self, pos, item):                  # 在指定位置添加元素
        if pos <= 0:
            self.add(item)
        elif pos > (self.length()-1):
            self.append(item)
        else:
            node = Node(item)
            cur = self.__head
            count = 0
            while count < (pos-1):                 # 移动到指定位置的前一个位置
                count += 1
                cur = cur.next
            node.next = cur.next
            cur.next = node
 
    def remove(self, item):                        # 删除一个元素
        if self.is_empty():                        # 若链表为空,则直接返回空
            return
        cur = self.__head                          # 将cur指向头节点
        pre = None
        while cur.next != self.__head:
            if cur.item == item:
                if cur == self.__head:             # 先判断此结点是否是头节点
                    # 头节点的情况,找尾节点
                    rear = self.__head
                    while rear.next != self.__head:
                        rear = rear.next
                    self.__head = cur.next
                    rear.next = self.__head
                else:
                    # 中间节点
                    pre.next = cur.next
                return
            else:
                pre = cur
                cur = cur.next
        # 退出循环,cur指向尾节点
        if cur.item == item:
            if cur == self.__head:
                #链表只有一个节点
                self.__head = None
            else:
                #pre.next = cur.next              
                pre.next = self.__head
 
    def search(self, item):   
        #查找节点是否存在                      
        if self.is_empty():
            return False
        cur = self.__head
        if cur.item == item:
            return True
        while cur.next != self.__head:
            cur = cur.next
            if cur.item == item:
                return True
        return False
 
if __name__ == '__main__':
    ll = SinCycLinkedlist()
    ll.add(1)
    ll.add(2)
    ll.append(3)
    print(ll)
    ll.append(3)
    ll.insert(2, 4)
    ll.insert(4, 5)
    ll.insert(0, 6)
    print(ll)
    print("length:", ll.length())
    ll.travel()
    print(ll.search(3))
    print(ll.search(7))
    ll.remove(1)
    ll.remove(10)
    print("length:", ll.length())
    ll.travel()

四. 双向链表

4.1定义

一种更复杂的链表是“双向链表”或“双面链表”。每个节点有两个链接:一个指向前一个节点,当此节点为第一个节点时,指向空值;而另一个指向下一个节点,当此节点为最后一个节点时,指向空值。所以,在这里一个节点包括了三部分,前驱、数据、后驱。

在这里插入图片描述

4.2 操作

is_empty() 链表是否为空
length() 链表长度
travel() 遍历链表
add(item) 链表头部添加
append(item) 链表尾部添加
insert(pos, item) 指定位置添加
remove(item) 删除节点
search(item) 查找节点是否存在

4.3 链表节点的实现

class Node(object):
    #双向链表节点
    def __init__(self, item):
        self.item = item
        self.next = None
        self.prev = None

4.4 操作实现

对于判断链表是否为空、链表长度、遍历链表,和单向链表差别不大
class DLinkList(object):
    #双向链表
    def __init__(self):
        self.__head = None
 
    def is_empty(self):
        #链表是否为空
        return self.__head == None
 
    def length(self):
        #链表的长度
        cur = self.__head
        count = 0
        while cur != None:
            count += 1
            cur = cur.next
        return count
 
    def travel(self):
        #遍历链表
        cur = self.__head
        while cur != None:
            print(cur.item)
            cur = cur.next

在这里插入图片描述

def add(self, item):
        #头部插入元素
        node = Node(item)
        if self.is_empty():
            self.__head = node
        else:
            node.next = self.__head
            self.__head = node
            node.next.prev = node
            #或者
            #node.next = self.__head
            #self.__head.prev = node
            #self.__head = node
            #代码不唯一
尾部插入元素,只要在单向链表的基础上加上pev的字段操作即可
def append(self, item):
        #尾部插入元素
        node = Node(item)
        if self.is_empty():
            self._head = node
        else:
            #cur移动到链表尾部
            cur = self._head
            while cur.next != None:
                cur = cur.next
            cur.next = node
            #将node的prev指向cur
            node.prev = cur
在指定位置添加节点:

在这里插入图片描述

def insert(self, pos, item):
        #在指定位置插入节点
        if pos <= 0:
            self.add(item)
        elif pos > (self.length()-1):
            self.append(item)
        else:
            node = Node(item)
            cur = self._head
            count = 0
            while count < (pos-1):
                count += 1
                cur = cur.next
            node.prev = cur
            node.next = cur.next
            cur.next.prev = node
            cur.next = node
 
删除元素:
def remove(self, item):
        #删除元素
        if self.is_empty():
            return
        else:
            cur = self._head
            if cur.item == item:
                if cur.next == None:
                    self._head = None
                else:
                    cur.next.prev = None
                    self._head = cur.next
                return
            while cur != None:
                if cur.item == item:
                    cur.prev.next = cur.next
                    cur.next.prev = cur.prev
                    break
                cur = cur.next
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值