zoukankan      html  css  js  c++  java
  • python实现单链表

    为什么需要链表?

    对于上部分顺序表的学习,我们了解到在构建顺序表时需要预先知道数据大小来申请连续的存储空间,而在进行扩充的时候又需要进行数据的搬迁,所以使用起来并不是很灵活。

    那我们就想,能不能存在一种数据结构是的在数据扩充的时候,在原有的数据完全不变化,扩充一个数据就增加一个,我们需要这样的一个数据结构,那么这样的数据结构怎么存储呢?

    比如构造了一组数据Li=[200],然后申请了一个存储空间将200存储下来,然后补充了一个数据400,Li=[200,400],这时候又申请了一个空间用来储存400,现在我们要做的是不利用顺序表的方式进行存储,把他们顺序链接在一起,并且也不考虑我们最终扩充多少的数据,即扩充一个数据就申请一个单元来储存它,比如在扩充一个数据600,数据结构Li=[200,400,600],那么就在申请一个空间来储存600。如下表所示,我们怎么吧这种离散的空间关联在一起呢?
    在这里插入图片描述
    上表的结构已经没有了连续的概念了,但是我们可以通过找一根线将它们串联起来,这个概念已经在顺序表中的元素外置中引入过,具体的做法是:首先申请一个空间存储元素200,在数据扩充个400以后,在申请一个空间用于存储,然后将200与400之间通过一条线进行连接,使之建立一种关系,同样在扩充600的时候,也会申请一个空间用于存储600,然后通过一条线将400与600进行链接,重复这个过程,就可以扩充任意个数据,当然这里暂时先不用明白这条线是怎么具体链接的,后续会详细讲解。如下表所示
    在这里插入图片描述
    这样链接好了以后,在想获取数据的时候就可以根据200,沿着这条线往下寻找,就能根据这条线将所有元素串联在一起,而且并不需要预估元素的占用空间是多大(整型数据和char)。这种数据结构就叫做链表。

    链表的定义

    链表(Linked list)是一种常见的基础数据结构。是一种线性表,但是不像顺序表一样连续存储数据,而是在每一个节点(数据存储单元)里存放下一个节点的位置信息(即地址)。
    在这里插入图片描述
    即在申请储存单元的时候,对单个的单元进行拓展,不仅保留该数据,还要保留另外的一部分数据,这两部分称为一个整体,叫做节点。其中第一部分保存数据,第二部分保存地址。而为了链接200和400这两个节点,就将第一个节点的链接区储存为400的地址,后面执行相同的步骤,这样就达到了一种线性关系,通过构建这样的一种数据结构来达到这样的链接关系。

    单项链表

    单项链表也叫单链表,是链表中最简单的一种形式,他的每个节点包含两个域,一个信息域(元素域)和一个链接域。这个链接指向链表中的下一个节点,而最后一个节点的链接域则指向一个空值。
    在这里插入图片描述
    在这里插入图片描述

    1. 表元素elem用来存放具体的数据。
    2. 链接域next用来存放下一个节点的位置(python中的标识)
    3. 变量p指向链表的头节点(首节点)的位置,从p出发能找到表中的任意节点。

    单链表的操作

    下面对该数据结构通过类的方式进行实现,一方面是指数据的保存,一方面是对数据的操作。
    具体操作包括:

    1. is_empty():链表是否为空
    2. length():链表长度
    3. travel():遍历链表
    4. add(item):链表头部添加元素
    5. append(item):链表尾部添加元素
    6. insert(pos,item):指定位置添加元素
    7. remove(item):删除节点
    8. delete(self, index):指定位置删除元素
    9. search(self,item):查找指定元素
    10. find(self,index):根据指定位置查找元素
    11. change(self,elem,index):根据指定位置替换值
    12. clear(self):清空链表
    13. sort(self):排序
    14. isExist(self,item):是否存在指定的元素
    15. __init__:初始化节点

    单链表实现操作

    # 单链表
    # 实现功能
    # 声明节点类
    class Node(object):
        # 初始化节点
        def __init__(self,elem):
            self.elem=elem
            self.next=None
    # 声明链表类
    class SingleLinkList(object):
        # 1、初始化置为空
        def __init__(self,node=None):
            self._head=node
        # 2、判断是否为空
        def is_empty(self):
            return self._head==None
        # 3、计算链表长度
        def length(self):
            cur=self._head
            count=0
            while cur != None:
                count=count+1
                cur=cur.next
            return count
        # 4、遍历链表
        def travel(self):
            cur=self._head
            while cur != None:
                print(cur.elem,end=" ")
                cur=cur.next
        # 5、头部添加元素
        def add(self,item):
            node=Node(item)
            node.next=self._head
            self._head=node
        #6、尾部追加元素
        def append(self,item):
            node=Node(item)
            if self.is_empty():
                self._head=node
            else:
                cur=self._head
                while cur.next !=None:
                    cur=cur.next
                cur.next=node
        #7、指定位置添加元素
        def insert(self,position,item):
            # 头插法
            if position<0:
                self.add(item)
            # 尾插法
            elif position>(self.length()-1):
                self.append(item)
            else:
                node=Node(item)
                pre=self._head
                count=0
                while count<(position-1):
                    pre=pre.next
                    count+=1
                    node.next=pre.next
                    pre.next=node
        # 8、删除指定元素
        def remove(self,item):
            cur=self._head
            pre=None
            while cur!=None:
                if cur.elem==item:
                    if cur==self._head:
                        self._head=cur.next
                    else:
                        pre.next=cur.next
                    break
                else:
                    pre=cur
                    cur=cur.next
        # 9、指定位置删除元素
        def delete(self, index):
            # 判空
            lgh=self.length()
            if self.is_empty():
                print('空链表')
                return
            if index < 0 or index > lgh:
                print('索引超过范围')
                return
    
            if index == 0:
                self._head = self._head.next
            else:
                pre = self._head
                for i in range(lgh):
                    if i == index - 1:
                        pre.next = pre.next.next
                        break
                    pre = pre.next
            lgh -= 1
            return
        # 10、查找指定的元素
        def search(self,item):
            cur=self._head
            while cur !=None:
                if cur.elem==item:
                    return True
                else:
                    cur=cur.next
                return False
        #11、根据指定位置查找元素
        def find(self,index):
            len=self.length()
            if self.is_empty():
                print('空链表')
            if index <0 or index >=len:
                print('索引超过范围')
                return
            node=self._head
            for i in range(len):
                if i == index:
                    return node.elem
                node = node.next
        # 12、根据位置替换值
        def change(self,elem,index):
            len=self.length()
            if self.is_empty():
                print('空链表')
                return
            if index <0 or index >=len:
                print('索引超出范围')
                return
            node = self._head
            for i in range(len):
                if i==index:
                    node.elem=elem
                    return
                node=node.next
        # 13、清空链表
        def clear(self):
            self._head=None
            len=self.length()
            len=0
        # 14、排序
        def sort(self):
            len=self.length()
            for i in range(0,len-1):
                current_node=self._head
                for j in range(0,len-i-1):
                    if current_node.elem>current_node.next.elem:
                        tmp=current_node.elem
                        current_node.elem=current_node.next.elem
                        current_node.next.elem=tmp
                    current_node=current_node.next
        # 15、是否存在指定的元素
        def isExist(self,item):
            count=0
            current_node=self._head
            for i in range(self.length()):
                if current_node.elem==item:
                    print("%d在链表中%d处
    " % (item, i + 1))  # i+1是在正常人认为的位置处,程序员一般是从0开始算起
                    count = 1
                current_node=current_node.next
            if count==0:
                print("%d不在链表中
    " % item)
    # 测试
    if __name__ == "__main__":
        lst = SingleLinkList()
        print(lst.is_empty())
        print(lst.length())
        lst.add(1)
        lst.travel()
        print()
        lst.append(10)
        lst.append(11)
        lst.append(12)
        lst.travel()
        print()
        lst.insert(2,7)
        lst.travel()
        print(lst.find(1))
        lst.remove(7)
        lst.travel()
        print()
        print(lst.search(1))
        lst.delete(1)
        lst.travel()
        print()
        lst.change(1,2)
        lst.travel()
        print()
        lst.sort()
        lst.travel()
        print()
        lst.isExist(1)
        lst.clear()

    结果

    
    

    C:Anaconda3python.exe "C:Program FilesJetBrainsPyCharm 2019.1.1helperspydevpydevconsole.py" --mode=client --port=65143
    import sys; print('Python %s on %s' % (sys.version, sys.platform))
    sys.path.extend(['C:\app\PycharmProjects', 'C:/app/PycharmProjects'])
    Python 3.7.6 (default, Jan 8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)]
    Type 'copyright', 'credits' or 'license' for more information
    IPython 7.12.0 -- An enhanced Interactive Python. Type '?' for help.
    PyDev console: using IPython 7.12.0
    Python 3.7.6 (default, Jan 8 2020, 20:23:39) [MSC v.1916 64 bit (AMD64)] on win32
    runfile('C:/app/PycharmProjects/DataStructure/LinkedList/single_linked_list.py', wdir='C:/app/PycharmProjects/DataStructure/LinkedList')
    True
    0
    1
    1 10 11 12
    1 10 7 11 12 10
    1 10 11 12
    True
    1 11 12
    1 11 1
    1 1 11
    1在链表中1处
    1在链表中2处

     

    链表和顺序表的对比

    链表失去了顺序表随机读取的优点,同时链表由于增加了节点的指针域,空间开销大,但对储存空间的使用要相对灵活。

    链表域顺序表的各种操作复杂度如下所示:

    操作链表顺序表
    访问元素 O(n) O(1)
    在头部插入/删除 O(1) O(n)
    在尾部插入/删除 O(n) O(1)
    在中间插入/删除 O(n) O(n)

    注意虽然表面上看起来复杂度都是O(n),但是链表和顺序表在插入和删除时进行的是完全不同的操作。链表的主要耗时操作是遍历查找,删除和插入操作本身的复杂度是O(1)。顺序表查找很快,主要耗时的操作是拷贝和覆盖。因为除了目标元素在尾部的特殊情况,顺序表进行插入和删除时需要对操作之间的元素进行前后移位操作,只能通过拷贝和覆盖的方法进行。

     
    1. search(item):查找节点是否存在
  • 相关阅读:
    C++ 项目和资源导引
    C++ 类再探
    C++ 语句函数再探
    leetcode-174. Dungeon Game 地下城游戏
    34. Find First and Last Position of Element in Sorted Array + 二分
    leetcode-27. Remove Element删除元素
    git 使用入门
    MySQL数据库的启动与停止
    C++类型转换
    C++ 获取对象类型
  • 原文地址:https://www.cnblogs.com/huanghanyu/p/13273934.html
Copyright © 2011-2022 走看看