• 「数据结构与算法之链表(Python)」(四)


    什么是链表

    顺序表的储存分为一体式结构和分离式结构,但总的来说存储数据的内存是一块连续的单元,每次申请前都要预估所需要的内存空间大小。这样就不能随意的增加我们需要的数据了。链接就是为了解决这个问题。它的数据存储方式是每插入一个数据,就在内存中申请一块存储空间来保存,那么新增加的数据如何和之前的数据保持关联呢?解决方法就是在原来的数据内存里保存新增加的数据的内存地址,这样就相当于用“一根线”把它们都串了起来,因此每次新插入一个数据,就要在内存中申请两个连续的空间,一个用来储存数据,一个用来储存下一个数据的地址。寻址方式就是从第一个数据开始依次往下寻找。

    (ps:图画的有点丑2333)

    另外,链表和顺序表统称为线性表。

    同时,我们需要一个内存空间,用来保存链表第一个数据的地址,因此,完整的结构应该是

    了解是链表的概念后,我们就要想办法来实现它,那么,用什么方式实现呢?

    我们知道,链表的实现需要把数据以及所支持的结构放到一起形成一个整体,这样才构成链表。这时就要用到面向对象中类的概念了。但因为链表其中还保存数据地址这个功能,我们就先要来学习先python中有关变量地址的一点知识。

    首先,我们知道,在其他语言,类似C语言中,表示地址用的是指针,但在python中根本没有指针这个类型,那我们要如何操作跟地址有关的概念呢?其实,python中定义变量和C语言是不一样的,在C语言中定义一个变量前需要声明变量的类型,例如:int c = 1。这样就相当于在内存中划出一块地方用来存放整数1。但在python中,为什么我们可以不用声明变量的类型就可以定义变量了呢?这是因为我们定义的那个变量保存的不是我们想要赋予变量的值,而是存放该值的内存地址,举个例子,如图:

    定义a = 10  b = 20,那么在内存中的存储方式为

    当进行交换后,a, b = b, a,此时:

    因此保存变量的的那块内存中的值根本没有变化,变化的是a和b中所指向的内存地址。

    把这种思想用到我们要实现的类中来,也就是类中存在两个内存,一个存放数据,一个存放下个节点的地址。当实例化一个对象后,elem保存数据的值,而next保存下一个对象的地址。如图:

    代码实现

    # coding:utf-8
    class SingleNode(object):
        """单链表的结点"""
        def __init__(self,elem):
            # _item存放数据元素
            self.elem = elem
            # _next是下一个节点的标识
            self.next = None
    
    
    class SingleLinkList(object):
        """单链表"""
        def __init__(self, node=None):
            self.__head = node
    
        def is_empty(self):
            """判断链表是否为空"""
            return self.__head == None
    
        def length(self):
            """链表长度"""
            # cur初始时指向头节点
            cur = self.__head
            count = 0
            # 尾节点指向None,当未到达尾部时
            while cur != None:
                count += 1
                # 将cur后移一个节点
                cur = cur.next
            return count
    
        def travel(self):
            """遍历链表"""
            cur = self.__head
            while cur != None:
                print(cur.elem, end=" ")
                cur = cur.next
    
        def add(self, elem):
            """头部添加元素"""
            # 先创建一个保存item值的节点
            node = SingleNode(elem)
            # 将新节点的链接域next指向头节点,即__head指向的位置
            node.next = self.__head
            # 将链表的头_head指向新节点
            self.__head = node
    
        def append(self, elem):
            """尾部添加元素"""
            node = SingleNode(elem)
            # 先判断链表是否为空,若是空链表,则将__head指向新节点
            if self.is_empty():
                self.__head = node
            # 若不为空,则找到尾部,将尾节点的next指向新节点
            else:
                cur = self.__head
                while cur.next != None:
                    cur = cur.next
                cur.next = node
    
        def insert(self, pos, elem):
            """指定位置添加元素"""
            # 若指定位置pos为第一个元素之前,则执行头部插入
            if pos <= 0:
                self.add(elem)
            # 若指定位置超过链表尾部,则执行尾部插入
            elif pos > (self.length() - 1):
                self.append(elem)
            # 找到指定位置
            else:
                node = SingleNode(elem)
                count = 0
                # pre用来指向指定位置pos的前一个位置pos-1,初始从头节点开始移动到指定位置
                pre = self.__head
                while count < (pos - 1):
                    count += 1
                    pre = pre.next
                # 先将新节点node的next指向插入位置的节点
                node.next = pre.next
                # 将插入位置的前一个节点的next指向新节点
                pre.next = node
    
        def remove(self, elem):
            """删除节点"""
            cur = self.__head
            pre = None
            while cur != None:
                # 找到了指定元素
                if cur.elem == elem:
                    # 如果第一个就是删除的节点
                    if cur == self.__head:
                        # 将头指针指向头节点的后一个节点
                        self.__head = cur.next
                    else:
                        # 将删除位置前一个节点的next指向删除位置的后一个节点
                        pre.next = cur.next
                    break
                else:
                    # 继续按链表后移节点
                    pre = cur
                    cur = cur.next
    
        def search(self, elem):
            """链表查找节点是否存在,并返回True或者False"""
            cur = self.__head
            while cur != None:
                if cur.elem == elem:
                    return True
                cur = cur.next
            return False
    
    # 测试
    if __name__ == "__main__":
        ll = SingleLinkList()
        ll.add(1)
        ll.add(2)
        ll.append(3)
        ll.insert(2, 4)
        print("length:",ll.length())
        ll.travel()
        print(ll.search(3))
        print(ll.search(5))
        ll.remove(1)
        print("length:",ll.length())
        ll.travel()

     双向链表

    # coding:utf-8
    
    class Node(object):
        """节点"""
        def __init__(self, elem):
            self.elem = elem
            self.prev = None
            self.next = None
    
    
    class DoubleLinkList(object):
        """单链表"""
        def __init__(self, node=None):
            self.__head = node
    
        def is_empty(self):
            """判断链表是否为空"""
            return self.__head == None
    
        def length(self):
            """链表长度"""
            # cur初始时指向头节点
            cur = self.__head
            count = 0
            # 尾节点指向None,当未到达尾部时
            while cur != None:
                count += 1
                # 将cur后移一个节点
                cur = cur.next
            return count
    
        def travel(self):
            """遍历链表"""
            cur = self.__head
            while cur != None:
                print(cur.elem, end=" ")
                cur = cur.next
    
        def add(self, elem):
            """头部添加元素"""
            # 先创建一个保存item值的节点
            node = Node(elem)
            # 将新节点的链接域next指向头节点,即__head指向的位置
            node.next = self.__head
            # 将链表的头_head指向新节点
            self.__head = node
            self.__head.prev = node
    
        def append(self, elem):
            """尾部添加元素"""
            node = Node(elem)
            # 先判断链表是否为空,若是空链表,则将__head指向新节点
            if self.is_empty():
                self.__head = node
            # 若不为空,则找到尾部,将尾节点的next指向新节点
            else:
                cur = self.__head
                while cur.next != None:
                    cur = cur.next
                cur.next = node
                node.prev = cur
    
        def insert(self, pos, elem):
            """指定位置添加元素"""
            # 若指定位置pos为第一个元素之前,则执行头部插入
            if pos <= 0:
                self.add(elem)
            # 若指定位置超过链表尾部,则执行尾部插入
            elif pos > (self.length() - 1):
                self.append(elem)
            # 找到指定位置
            else:
                cur = self.__head
                count = 0
                while count < pos:
                    count += 1
                    cur = cur.next
                node = Node(elem)
                node.next = cur
                node.prev = cur.prev
                cur.prev.next = node  # cur.prev = node
                cur.prev = node  # cur.prev.next = node
    
        def remove(self, elem):
            """删除节点"""
            cur = self.__head
            while cur != None:
                # 找到了指定元素
                if cur.elem == elem:
                    # 如果第一个就是删除的节点
                    if cur == self.__head:
                        # 将头指针指向头节点的后一个节点
                        self.__head = cur.next
                        if cur.next:  # 判断链表是不是只有一个结点
                            cur.next.prev = None
                    else:
                        # 将删除位置前一个节点的next指向删除位置的后一个节点
                        cur.prev.next = cur.next
                        if cur.next:  # 判断该结点是不是链表最后一个
                            cur.next.prev = cur.prev
                    break
                else:
                    # 继续按链表后移节点
                    cur = cur.next
    
        def search(self, elem):
            """链表查找节点是否存在,并返回True或者False"""
            cur = self.__head
            while cur != None:
                if cur.elem == elem:
                    return True
                cur = cur.next
            return False
    
    
    # 测试
    if __name__ == "__main__":
        d = DoubleLinkList()
        d.add(1)
        d.add(2)
        d.append(3)
        d.insert(2, 4)
        print("length:",d.length())
        d.travel()
        print(d.search(3))
        print(d.search(5))
        d.remove(2)
        print("length:",d.length())
        d.travel()

     

  • 相关阅读:
    vue 子页面,向父页面 传值...
    pre 标签 防止 其撑开 div...
    Vue 父页面 值传递 不到 子组件....
    Mysql tips 功能...
    mysql 配置utf8 编码,支持 emoji 方法!!!
    DataGrip 使用--方法-..../
    百度地图 api bug 解决.......
    民生银行信用卡销卡指南
    古董留念
    Microsoft Office 2010 Service Pack 2 发布更新
  • 原文地址:https://www.cnblogs.com/linyuhong/p/9864135.html
Copyright © 2020-2023  润新知