HuaPu在学:Python数据结构与算法【链表】


前言

以下是花圃在学习Python的数据结构与算法的一些要点内容笔记。


链表(Linked list)是一种常见的基础数据结构,是一种线性表,但是并不会按线性的顺序存储数据,而是在每一个节点里存到下一个节点的指针(Pointer)。由于不必须按顺序存储,链表在插入或删除的时候最快可以达到O(1)的复杂度(告诉节点地址的情况下),比另一种线性表顺序表快得多,但是查找一个节点或者访问特定编号的节点则需要O(n)的时间,而顺序表相应的时间复杂度分别是O(logn)和O(1)。
使用链表结构可以克服数组链表需要预先知道数据大小的缺点,链表结构可以充分利用计算机内存空间,实现灵活的内存动态管理。但是链表失去了数组随机读取的优点,同时链表由于增加了结点的指针域,空间开销比较大。

【程序本身很多可以优化的地方,只是供参考思路】

一、单向链表

之前我们提到的一种的数据结构是顺序表,顺序表实际上是向操作系统OS申请开辟一段连续的连续的存储空间,不管是外置还是不外置,那么我现在不希望我提前去估计我要用多大的空间,那么我们就引入了链表。

链表就是通过一个元素通过存储下一个元素的地址(位置)去将两者串联起来,这里注意无论是顺序表还是链表我们都不难发现,他们属于一维的线性表。如何实现通过上一个元素找到下一个元素位置???

我单独存储一个元素是无法找到下一个元素的。那么就需要我既要有数据,又有指向,那么这个时候数据存储的地方是数据区,紧接着会有一个指向下一个元素的指针,被称作链接区,这个时候两者合称结点。

单向列表的概念就是只有一个指向,单向存储,头部叫做头节点,会有一个指向头部存储的地址,尾部称作尾节点,尾节点的最后一个链接区地址是空。

那么我们知道单向列表既然属于数据结构,那么对于一种数据结构实际上是一对象,我们就可以把该对象以及操作方法封装成类。这实际上就是我们在顺序表里引入的ADT模型。

我们来试着实现这样的数据结构,实际上python中的元组类型完全可以满足节点的两两组合,但我们不去考虑python的特殊性,考虑一般程序的普适性。

# 定义节点类:(传入想要存储的数据)(数据区之外的链接区起始为空)
class Node(object):
    def __init__(self,elem):
        self.elem=elem
        self.next=None
        pass
    pass

# 定义单向连接关系类,与支持操作封装到一起
class Singlelinklist(object):
    def __init__(self,node=None):
        self.__head=node
        pass

    def is_empty(self):
        """是否为空"""
        return self.__head==None

    def length(self):
        """长度"""
        cur=self.__head
        count=0
        while cur!=None:
            count+=1
            cur=cur.next
            pass
        return count

    def travel(self):
        """遍历"""
        cur=self.__head
        while cur!=None:
            print(cur.elem,end=" ")
            cur=cur.next
            pass
        print("\n")
        pass

    def append(self,item):
        """尾插法"""
        node=Node(item)
        if self.__head==None:
            self.__head=node
            pass
        else:
            cur = self.__head
            while cur.next!=None:
                cur=cur.next
                pass
            cur.next=node
        pass

    def add(self,item):
        """头插法"""
        node=Node(item)
        node.next=self.__head
        self.__head=node
        pass

    def insert(self,pop,item):
        """任意位置插入"""
        node=Node(item)
        count=0
        if pop<=0:
            self.add(item)
            pass
        elif pop>self.length()-1:
            self.append(item)
            pass
        else:
            cur=self.__head
            while cur!=None:
                count+=1
                cur=cur.next
                if count==pop-1:
                    node.next = cur.next
                    cur.next = node
                    break
                pass
            pass
        pass

    def search(self,item):
        """寻找某个元素在链表中的位置"""
        cur=self.__head
        count=0
        while cur!=None:
            count+=1
            if cur.elem==item:
                return count-1,True
            else:
                cur=cur.next
                pass
            pass
        return "不存在",False

    def remove(self,item):
        """移除某个元素"""
        cur=self.__head
        pre=None
        while cur!=None:
            if cur.elem==item:
                if cur==self.__head:
                    self.__head=cur.next
                    pass
                else:
                    pre.next=cur.next
                    pass
                break
                pass
            else:
                pre=cur
                cur=cur.next
                pass
            pass
        pass

    pass

if __name__=="__main__":
    ll=Singlelinklist()
    print(ll.is_empty())
    print(ll.length())
    #结果应该是True,0
    print("=====================================")
    ll.append(1)
    print(ll.is_empty())
    print(ll.length())
    #结果应该是False,1
    print("=====================================")
    ll.append(2)
    ll.append(3)
    ll.append(4)
    ll.travel()
    # 结果应该是1 2 3 4
    print("=====================================")
    ll.add(5)
    ll.travel()
    # 结果应该是5 1 2 3 4
    print("=====================================")
    ll.insert(-1,6)
    ll.travel()
    #结果应该是6 5 1 2 3 4
    ll.insert(10,7)
    ll.travel()
    # 结果应该是 6 5 1 2 3 4 7
    ll.insert(2,100)
    ll.travel()
    # 结果应该是6 5 100 1 2 3 4 7
    print("=====================================")
    print(ll.search(100))
    print(ll.search(200))
    #结果应该是(2, True)  ('不存在', False)
    print("=====================================")
    ll.remove(100)
    ll.travel()
    ll.remove(7)
    ll.travel()
    ll.remove(6)
    ll.travel()
    #结果应该是6 5 1 2 3 4 7    6 5 1 2 3 4     5 1 2 3 4
True
0
=====================================
False
1
=====================================
1 2 3 4 

=====================================
5 1 2 3 4 

=====================================
6 5 1 2 3 4 

6 5 1 2 3 4 7 

6 5 100 1 2 3 4 7 

=====================================
(2, True)
('不存在', False)
=====================================
6 5 1 2 3 4 7 

6 5 1 2 3 4 

5 1 2 3 4 

单链表与顺序表的对比
访问: O(n) O(1)
头插法:O(1) O(n)
尾插法:O(n) O(1)
中间: O(n) O(n)
链表会多占内存,但是链表又是分散存取内存,顺序表必须是连续空间,不方便改动,比较大数据可能就需要申请很大的连续空间,而链表可以利用内存中离散的空间,在访问的时候,链表必须是顺序,而顺序表可以通过计算一步到位,而且注意虽然时间复杂度有的时候相同,但一个是遍历,另一个是内存空间数据的搬迁。

二、双向链表

这个时候我们需要引入两个概念,在单向链表中,有元素区有链接区,那么链接区指向的是下一个元素的位置,也就是说我想找某一个元素的上一个位置的元素,我依然要从头开始,那么有了双向结点就不同了,双向节点是有元素区、前驱区、后继区组成的,也就是我的后继区域仍然是当前指向下一个位置,前驱区域就是指向前一个区域的了,元素区存储数据。

到这里我们可以注意到,顺序表、单向链表、双向链表,我们都是在抽象一种数据类型,将数据类型的属性操作方法都封装,归为一类,称作抽象数据类型ADT。

class Node(object):
    def __init__(self,elem):
        self.elem=elem
        self.next=None
        self.prev=None
        pass
    pass

class Double_singlelinklist():
    def __init__(self,node=None):
        self.__head=node
        pass

    def is_empty(self):
        """是否为空"""
        return self.__head==None

    def length(self):
        """长度"""
        cur=self.__head
        count=0
        while cur!=None:
            count+=1
            cur=cur.next
            pass
        return count

    def travel(self):
        """遍历"""
        cur=self.__head
        while cur!=None:
            print(cur.elem,end=" ")
            cur=cur.next
            pass
        print("\n")
        pass

    def append(self,item):
        """尾插法"""
        node=Node(item)
        if self.__head==None:
            self.__head=node
            pass
        else:
            cur = self.__head
            while cur.next!=None:
                cur=cur.next
                pass
            cur.next=node
            node.prev=cur                                #与单向不同1
        pass

    def add(self,item):
        """头插法"""
        node=Node(item)
        node.next=self.__head
        self.__head=node
        node.next.prev=node                             #与单向的不同2
        #或者  self.__head.pre=node的方式置前
        pass


    def insert(self,pop,item):
        """任意位置插入"""
        node=Node(item)
        count=0
        if pop<=0:
            self.add(item)
            pass
        elif pop>self.length()-1:
            self.append(item)
            pass
        else:
            cur=self.__head
            while cur!=None:
                count+=1
                cur=cur.next
                if count==pop-1:
                    node.next = cur                       #与单向的方式不同3
                    node.prev=cur.prev
                    cur.prev.next=node
                    cur.prev=node
                    break
                pass
            pass
        pass

    def search(self,item):
        """寻找某个元素在链表中的位置"""
        cur=self.__head
        count=0
        while cur!=None:
            count+=1
            if cur.elem==item:
                return count-1,True
            else:
                cur=cur.next
                pass
            pass
        return "不存在",False

    def remove(self,item):       #与单向不同4
        """移除某个元素"""
        cur=self.__head
        while cur!=None:
            if cur.elem==item:
                if cur==self.__head:
                    self.__head=cur.next
                    if cur.next==None:
                        cur.next.prev=None
                        pass
                    pass
                else:
                    cur.prev.next=cur.next
                    if cur.next!=None:
                        cur.next.prev=cur.prev
                        pass
                    pass
                break
                pass
            else:
                cur=cur.next
                pass
            pass
        pass
    pass

if __name__=="__main__":
    ll = Double_singlelinklist()
    print(ll.is_empty())
    print(ll.length())
    # 结果应该是True,0
    print("=====================================")
    ll.append(1)
    print(ll.is_empty())
    print(ll.length())
    # 结果应该是False,1
    print("=====================================")
    ll.append(2)
    ll.append(3)
    ll.append(4)
    ll.travel()
    # 结果应该是1 2 3 4
    print("=====================================")
    ll.add(5)
    ll.travel()
    # 结果应该是5 1 2 3 4
    print("=====================================")
    ll.insert(-1, 6)
    ll.travel()
    # 结果应该是6 5 1 2 3 4
    ll.insert(10, 7)
    ll.travel()
    # 结果应该是 6 5 1 2 3 4 7
    ll.insert(2, 100)
    ll.travel()
    # 结果应该是6 5 100 1 2 3 4 7
    print("=====================================")
    print(ll.search(100))
    print(ll.search(200))
    # 结果应该是(2, True)  ('不存在', False)
    print("=====================================")
    ll.remove(100)
    ll.travel()
    ll.remove(7)
    ll.travel()
    ll.remove(6)
    ll.travel()
    # 结果应该是6 5 1 2 3 4 7    6 5 1 2 3 4     5 1 2 3 4
True
0
=====================================
False
1
=====================================
1 2 3 4 

=====================================
5 1 2 3 4 

=====================================
6 5 1 2 3 4 

6 5 1 2 3 4 7 

6 100 5 1 2 3 4 7 

=====================================
(1, True)
('不存在', False)
=====================================
6 5 1 2 3 4 7 

6 5 1 2 3 4 

5 1 2 3 4 

三、单向循环链表

class Node(object):
    def __init__(self,elem):
        self.elem=elem
        self.next=None
        pass
    pass


class Singlecyclelinklist(object):
    def __init__(self,node=None):
        self.__head=node
        if node:
            node.next=node
            pass
        pass

    def is_empty(self):
        """是否为空"""
        return self.__head is None

    def length(self):
        """长度"""
        if self.is_empty():
            return 0
        else:
            cur=self.__head
            count=1
            while cur.next!=self.__head:
                count+=1
                cur=cur.next
                pass
            return count

    def travel(self):
        """遍历"""
        if self.is_empty():
            return 0
        else:
            cur=self.__head
            while cur.next!=self.__head:
                print(cur.elem,end=" ")
                cur=cur.next
                pass
            print(cur.elem, end=" ")
        print("\n")
        pass

    def append(self,item):
        """尾插法"""
        node=Node(item)
        if self.is_empty():
            node.next=node
            self.__head=node
            pass
        else:
            cur = self.__head
            while cur.next!=self.__head:
                cur=cur.next
                pass
            node.next=self.__head
            cur.next=node
            pass
        pass

    def add(self,item):
        """头插法"""
        node=Node(item)
        if self.is_empty():
            self.__head = node
            node.next = node
            pass
        elif self.is_empty()==1:
            node.next=self.__head
            self.__head.next = node
            self.__head=node
        else:
            cur=self.__head
            while cur.next!=self.__head:
                cur=cur.next
                pass
            cur.next=node
            node.next=self.__head
            self.__head=node
            pass

    def insert(self,pop,item):
        """任意位置插入"""
        node=Node(item)
        count=0
        if pop<=0:
            self.add(item)
            pass
        elif pop>self.length()-1:
            self.append(item)
            pass
        else:
            cur=self.__head
            while cur.next!=self.__head:
                count+=1
                cur=cur.next
                if count==pop-1:
                    node.next=cur.next
                    cur.next = node
                    break
                pass
            pass
        pass

    def search(self,item):
        """寻找某个元素在链表中的位置"""
        if self.is_empty():
            return "不存在",False
        else:
            cur=self.__head
            count=0
            while cur.next!=self.__head:
                count+=1
                if cur.elem==item:
                    return count-1,True
                else:
                    cur=cur.next
                    pass
                pass
        if cur.elem==item:
            return count,True
        return "不存在",False

    def remove(self,item):
        """移除某个元素"""
        if self.is_empty():
            return False
        else:
            cur=self.__head
            pre=None
            while cur.next!=self.__head:
                if cur.elem==item:
                    if cur==self.__head:
                        cur1 = self.__head
                        while cur1.next!=self.__head:
                            cur1 = cur1.next
                            pass
                        self.__head=cur.next
                        cur1.next=self.__head
                        pass
                    else:
                        pre.next=cur.next
                        pass
                    return                 #注意这里不能用break,break只是退出循环,后面if不该执行的情况仍然会执行,所以应该是return退出整个
                else:
                    pre=cur
                    cur=cur.next
                    pass
            if cur.elem==item:
                if cur==self.__head:
                    self.__head=None
                    pass
                else:
                    pre.next=cur.next
                    pass
                pass
            pass
        pass

    pass

if __name__=="__main__":
    ll=Singlecyclelinklist()
    print(ll.is_empty())
    print(ll.length())
    #结果应该是True,0
    print("=====================================")
    ll.add(1)
    ll.add(2)
    ll.add(3)
    ll.travel()
    print("=====================================")
    ll.append(4)
    ll.append(5)
    ll.append(6)
    ll.travel()
    print("=====================================")
    ll.insert(-1,100)
    ll.insert(10,200)
    ll.insert(2,300)
    ll.travel()
    print("=====================================")
    print(ll.search(300))
    print(ll.search(4))
    print(ll.search(11))
    print("=====================================")
    ll.remove(100)
    ll.travel()
    ll.remove(200)
    ll.travel()
    ll.remove(300)
    ll.travel()
    print("=====================================")
True
0
=====================================
3 2 1 

=====================================
3 2 1 4 5 6 

=====================================
100 3 300 2 1 4 5 6 200 

=====================================
(2, True)
(5, True)
('不存在', False)
=====================================
3 300 2 1 4 5 6 200 

3 300 2 1 4 5 6 

3 2 1 4 5 6 

=====================================

四、双向循环链表

class DoubleListNode(object):
    """双向节点类"""
    def __init__(self, _item, _prev=None, _next=None):
        self.item = _item
        self.prev = _prev
        self.next = _next
        pass
    pass
    
class DoubleCircleLinkedList(SingleCircleLinkedList):
    """双向循环链表类"""
    def __init__(self):
        self.head = None

    def add(self, newdata):
        node = DoubleListNode(newdata)
        if self.is_empty():
            self.head = node
            node.prev = node
            node.next = node
        else:
            node.prev = self.head.prev
            node.next = self.head
            self.head.prev.next = node
            self.head.prev = node
            self.head = node

    def append(self, newdata):
        node = DoubleListNode(newdata)
        if self.is_empty():
            self.head = node
            node.prev = node
            node.next = node
        else:
            self.head.prev.next = node
            self.head.prev = node
            node.prev = self.head.prev
            node.next = self.head

    def insert(self, pos, newdata):
        if pos <= 0:
            self.add(newdata)
        elif pos > self.length() - 1:
            self.append(newdata)
        else:
            node = DoubleListNode(newdata)
            cur = self.head
            count = 0
            while count < pos - 1:
                count += 1
                cur = cur.next
            node.next = cur.next
            cur.next.prev = node
            node.prev = cur
            cur.next = node

    def remove(self, olddata):
        if self.is_empty():
            return
        elif self.head.item == olddata:
            if self.length() == 1:
                self.head = None
            else:
                self.head.prev.next = self.head.next
                self.head.next.prev = self.head.prev
                self.head = self.head.next
        else:
            cur = self.head.next
            while cur != self.head:
                if cur.item == olddata:
                    cur.prev.next = cur.next
                    cur.next.prev = cur.prev
                cur = cur.next

顺序表和链表统称线性表,存储线性数据,那么怎么去利用???
看下一节笔记“栈”。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值