链表的介绍_以Python为例

数据结构篇——链表(以Python为例)

一、链表介绍

链表(link list)的顺序是由链表中的指针决定的,其为动态结合提供了一种简单而灵活的表示方法。链表在存储单元上非连续、非顺序。其节点包含两个部分:数据域与指针域,数据域存储该节点的数据元素,指针域存储指向下一个节点的指针。

二、链表
1. 单向链表

​ 单向链表又名单链表,是一种顺序存储的结构。head指针指向头节点,尾节点的指针指向None,item存储节点数据,next指向下一个节点。

  • 定义节点
class Node(object):
    """单链表的节点"""

    def __init__(self, item):
        # item存放数据元素
        self.item = item
        # 初始化节点的指针为None,next是指向一个节点的指针,
        self.next = None
  • 定义链表
class SingleLinkList(object):
    """单链表类"""

    def __init__(self):
        self._head = None

    def is_empty(self):
        """判断链表是否为空"""
        # None 返回True,非None返回False.
        return self._head is None

    def length(self):
        """链表长度"""
        # 初始指针指向head
        cur = self._head
        count = 0
        # 指针指向None 表示到达尾部
        while cur is not None:
            count += 1
            # 指针下移
            cur = cur.next
        return count

    def items(self):
        """遍历链表"""
        cur = self._head
        while cur is not None:
            # 调用生成器,返回一个迭代器
            yield cur.item
            # print(cur.item)
            cur = cur.next

    def add(self, item):
        """向链表头部添加元素"""
        # 创建一个以item为元素的节点node
        node = Node(item)
        # 新节点的指针指向链表的原头部节点
        node.next = self._head
        # 头部节点的指针修改为新增加的节点
        self._head = node

    def append(self,item):
        """在链表尾部添加元素"""
        # 创建一个以item为元素的节点node
        node = Node(item)
        # 先判断是否为空链表
        if self._head is None:
            """若为空链表,则链表的头部指向新节点"""
            self._head = node
        else:
            """若不是空链表,则找到链表尾部,将尾部节点的next指向新节点"""
            cur = self._head
            while cur.next is not None:
                cur = cur.next
            cur.next = node

    def insert(self, index, item):
        """在指定位置插入元素"""
        if index <= 0:                  # 指定位置在第一个元素之前,在头部插入
            self.add(item)
        elif index > self.length() - 1: # 指定位置超出链表尾部,在尾部插入
            self.append(item)
        else:
            node = Node(item)
            cur = self._head
            count = 0
            while count < index-1:
                cur = cur.next
                count += 1
            # 在插入节点时,先连接后面的节点,再连接前面的节点
            node.next = cur.next
            cur.next = node

    def remove(self, item):
        """删除链表中的节点"""
        if self.is_empty():
            print("链表为空,不能删除此节点")
        else:
            # 当第一个元素为要删除的元素
            if self._head.item == item:
            	self._head = self._head.next
            else:
                cur = self._head
                pre = None  # 用于记录被删除节点的前一个节点
                while cur is not None:      # 当删除的元素不是第一个元素时
                    # 找到指定的元素之后,将所删除节点的前一个结点指向所删除节点的后一个节点,并退出判断
                    if cur.item == item:
                        pre.next = cur.next
                        return
                    else:
                        pre = cur
                        cur = cur.next

    def find(self, item):
        """查找元素是否存在"""
        return item in self.items()
  • 链表的使用
if __name__ == '__main__':
    link_list = SingleLinkList()
    node1 = Node(1)
    node2 = Node(2)
    node3 = Node(4)
    node4 = Node(5)
    # 将节点添加到链表,使得链表的头指针指向node1
    link_list._head = node1
    # 将第一个节点的指针指向下一个节点
    node1.next = node2
    node2.next = node3
    node3.next = node4
    # 判断链表是否为空
    # print(link_list.is_empty())

    # 计算链表长度
    # print(link_list.length())

    # 遍历链表
    for i in link_list.items():
        print(i, end=" ")
    print("\n")

    # 在链表头部增加节点
    link_list.add(3)
    for i in link_list.items():
        print(i, end=" ")
    print("\n")

    # 在链表尾部增加节点
    link_list.append(7)
    for i in link_list.items():
        print(i, end=" ")
    print("\n")

    # 在链表指定位置插入节点
    link_list.insert(1, 8)
    for i in link_list.items():
        print(i, end=" ")
    print("\n")

    # 删除链表中的元素
    link_list.remove(7)
    for i in link_list.items():
        print(i, end=" ")
    print("\n")

    # 查找元素是否在链表中
    print(link_list.find(7))
2. 单向循环链表

​ 单向循环链表在单向链表的基础上,将尾节点与头节点连接在一起了,即将尾节点的指针指向头节点,变成单向循环链表。

  • 定义节点
class Node(object):
    """单循环链表的节点"""
    def __init__(self, item):
        # item存放链表元素
        self.item = item
        # 初始化节点的指针为None,next是指向下一个节点的指针,
        self.next = None
  • 定义链表
class SingleCycleLinkList(object):
    """单向循环链表类"""

    def __init__(self):
        self._head = None

    def is_empty(self):
        """判断链表是否为空"""
        return self._head is None

    def length(self):
        """计算链表长度"""
        count = 0
        cur = self._head
        if self._head is None:      # 当链表为空时,返回0
            return count
        else:
            while cur.next != self._head:
                count += 1
                cur = cur.next
            return count+1

    def items(self):
        """遍历链表"""
        # 当链表为空时
        if self.is_empty():
            print("链表为空")
        else:
            cur = self._head
            while cur.next != self._head:
                # 调用生成器,返回一个迭代器
                yield cur.item
                cur = cur.next
            yield cur.item  # 最后一个节点的元素值未输出,因此,在此处输出

    def add(self, item):
        """在链表头部添加节点"""
        # 创建节点
        node = Node(item)
        # 链表头部指向新增加的节点
        if self.is_empty():                 # 当链表为空时
            self._head = node
            node.next = node
        else:
            cur = self._head
            node.next = self._head          # 将添加的节点指针指向头部
            while cur.next != self._head:   # 找到尾部节点,使得尾部节点的指针指向新添加的节点
                cur = cur.next
            cur.next = node
            self._head = node               # 修改head指向新增加的节点

    def append(self, item):
        """在链表尾部添加节点"""
        # 创建节点
        node = Node(item)
        if self.is_empty():             # 当链表为空时
            self._head = node
            node.next = node
        else:
            cur = self._head
            node.next = cur             # 新增加的节点指针指向头节点
            while cur.next != self._head:
                cur = cur.next
            cur.next = node             # 链表尾部节点指针指向新增加的节点

    def insert(self, index, item):
        """在指定位置插入元素"""
        # 创建节点
        node = Node(item)
        if index <= 0:                  # 指定位置在第一个元素之前,在头部插入
            self.add(item)
        elif index > self.length() - 1: # 指定位置超出链表尾部,在尾部插入
            self.append(item)
        else:
            cur = self._head
            count = 0
            while count < index - 1:
                count += 1
                cur = cur.next
            # 在插入节点时,先连接后面的节点,再连接前面的节点
            node.next = cur.next
            cur.next = node

    def remove(self, item):
        """删除链表中的节点"""
        if self.is_empty():
            print("链表为空,不能删除此节点")
        else:
            cur = self._head
            # 当第一个节点为要删除的元素时
            if self._head.item == item:
                # 当链表只有一个节点,即头节点时,将head指针指向None
                if self._head.next == self._head:
                    self._head = None
                # 当链表不止一个节点时
                else:
                    while cur.next != self._head:       # 遍历找到尾节点
                        cur = cur.next
                    self._head = self._head.next        # 将head指针指向头节点的下一个节点,即原链表的第二个节点
                    cur.next = self._head               # 将尾节点的指针指向更新后链表的头节点,即原链表的第二个节点
            else:
                # 当被删除的元素不是头节点时
                pre = None
                while cur.next != self._head:           # 遍历链表,但是遍历不到尾节点就退出循环了
                    # 找到指定的元素之后,将所删除节点的前一个结点指向所删除节点的后一个节点,并退出判断
                    if cur.item == item:
                        pre.next = cur.next
                        return
                    else:
                        pre = cur
                        cur = cur.next
                # while循环不能遍历到链表尾节点,在此处添加对尾节点的判断
                if cur.item == item:
                    pre.next = cur.next
                    return

    def find(self, item):
        """查找元素是否存在"""
        return item in self.items()
  • 链表的使用
if __name__ == '__main__':
    # 创建一个链表
    link_list = SingleCycleLinkList()
    node1 = Node(1)
    node2 = Node(2)
    node3 = Node(3)
    node4 = Node(4)
    node5 = Node(5)
    # 将节点添加至链表,使得链表的头指针指向节点
    link_list._head = node1
    node1.next = node2
    node2.next = node3
    node3.next = node4
    node4.next = node5
    node5.next = node1

    # 判断链表是否为空
    print(link_list.is_empty())

    # 计算链表长度
    print(link_list.length())

    # 遍历链表
    for item in link_list.items():
        print(item, end=" ")
    print("\n")

    # 在链表头部添加节点
    link_list.add(0)
    for item in link_list.items():
        print(item, end=" ")
    print("\n")

    # 在链表尾部添加节点
    link_list.append(6)
    for item in link_list.items():
        print(item, end=" ")
    print("\n")

    # 在链表指定位置插入节点
    link_list.insert(3, 30)
    for item in link_list.items():
        print(item, end=" ")
    print("\n")

    # 删除元素为item的节点
    link_list.remove(0)
    for item in link_list.items():
        print(item, end=" ")
    print("\n")

    # 查找元素是否在链表中
    print(link_list.find(3))
3. 双链表

双向链表在单向链表的基础上又多了一个指针域pre,每个节点包含元素值item,指向下一个节点的指针next,指向上一个节点的指针pre。当节点为头节点(head)时,pre指向None,当节点为尾节点(tail)时,next指向None。

  • 定义节点
class Node(object):
    """双向链表的节点"""

    def __init__(self, item):
        # item存放数据元素
        self.item = item
        # 初始化节点的指针为None,next是指向下一个节点的指针,
        self.next = None
        # 初始化节点的指针为None,pre是指向上一个节点的指针
        self.pre = None
  • 定义链表
class BilateralLinkList(object):
    """双向链表类"""

    def __init__(self):
        self._head = None

    def is_empty(self):
        """判断链表是否为空"""
        return self._head is None

    def length(self):
        """计算链表长度"""
        count = 0
        cur = self._head
        # 遍历到尾节点的距离
        while cur is not None:
            count += 1
            cur = cur.next
        return count

    def items(self):
        """遍历链表"""
        if self.is_empty():                     # 当链表为空时
            print("链表为空链表,无法遍历...")
            return
        cur = self._head
        while cur is not None:
            # 调用生成器,返回一个迭代器
            yield cur.item
            cur = cur.next

    def add(self, item):
        """在链表头部添加节点"""
        # 创建一个以item为元素的节点node
        node = Node(item)
        if self.is_empty():
            self._head = node
        else:
            self._head.pre = node       # 原始头节点的pre指针指向新增加的节点
            node.next = self._head      # 新增加节点的next指针指向原始头节点
            self._head = node           # head指针指向新增加的节点,将此节点作为头节点

    def append(self, item):
        """在链表尾部添加节点"""
        # 创建一个以item为元素的节点node
        node = Node(item)
        if self.is_empty():
            self._head = node
        else:
            cur = self._head
            while cur.next is not None:  # 遍历找到尾节点
                cur = cur.next
            cur.next = node             # 原始尾节点的next指针指向新增加的节点
            node.pre = cur              # 新增加节点的pre指针指向原始尾节点

    def insert(self, index, item):
        """在链表指定位置插入节点"""
        # 创建一个以item为元素的节点node
        node = Node(item)
        # 当指定位置在头节点前面时
        if index <= 0:
            self.add(item)
        # 当指定位置在尾节点后面时
        elif index >= self.length():
            self.append(item)
        # 当指定位置在链表中间时
        else:
            cur = self._head
            count = 0
            while count < index:
                count += 1
                cur = cur.next
            cur.pre.next = node     # 插入点位置的前一个节点的next指针指向新增加的节点
            node.pre = cur.pre      # 插入点的pre指针指向插入点位置的前一个结点
            node.next = cur         # 插入点的next指针指向插入点位置的后一个节点
            cur.pre = node          # 插入点位置的后一个节点的pre指针指向新增加的节点

    def remove(self, item):
        """删除链表中的节点"""
        if self.is_empty():
            print("链表为空,无法删除节点....")
        else:
            # 当删除的节点为头节点时
            if self._head.item == item:
                # 当链表只包含一个元素时
                if self._head.next is None:
                    self._head = None
                # 当链表不止一个元素时
                else:
                    self._head.next.pre = None          # 将第二个节点的pre指针指向None
                    self._head = self._head.next        # 将head指针指向原始链表的第二个节点
            else:
                cur = self._head
                # 当删除的节点不为头节点时
                while cur.next is not None:      # 遍历链表,但是遍历不到尾节点就退出循环了
                    if cur.item != item:
                        cur = cur.next
                    else:
                        cur.next.pre = cur.pre
                        cur.pre.next = cur.next
                        return
                if cur.item == item:        # 当要删除的节点为尾节点时
                    cur.pre.next = None

    def find(self, item):
        return item in self.items()
  • 链表的使用
if __name__ == '__main__':
    print("双向链表程序开始执行...")
    link_list = BilateralLinkList()

    # 在链表头部增加节点
    list_head = [5, 4, 3, 2, 1, 0]
    for i in list_head:
        link_list.add(i)

    # 判断链表是否为空
    print(link_list.is_empty())

    # 计算链表长度
    print(link_list.length())

    # 遍历链表元素
    for item in link_list.items():
        print(item, end=" ")
    print("\n")

    # 在链表尾部增加节点
    list_tail = [6,7,8,9,10]
    for i in list_tail:
        link_list.append(i)
    for item in link_list.items():
        print(item, end=" ")
    print("\n")

    # 在链表指定位置中插入节点
    link_list.insert(6, 30)
    for item in link_list.items():
        print(item, end=" ")
    print("\n")

    # 删除节点
    link_list.remove(10)
    for item in link_list.items():
        print(item, end=" ")
    print("\n")

    # 查找元素是否存在
    print(link_list.find(11))
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
好的,下面我将用约瑟夫问题为例,讲授Python链表节点的访问与遍历。 首先,我们需要了解链表的基本概念和操作。链表是一种常见的数据结构,由一系列节点构成,每个节点包含一个数据域和一个指向下一个节点的指针域。它可以用来存储任意类型的数据,常用于实现队列、栈、哈希表等数据结构链表有很多种类型,如单向链表、双向链表、循环链表等。 接下来,我们来介绍如何用Python链表来实现约瑟夫问题的求解。 约瑟夫问题的具体描述为:有n个人围成一圈,从第1个人开始报数,数到m的那个人出列,然后从出列的下一个人开始报数,数到m的那个人又出列,依次类推,直到所有人都出列为止。问最后出列的那个人的编号是多少? 我们可以用一个循环链表来模拟这个过程。具体实现步骤如下: 1. 创建一个循环链表,将n个人的编号依次加入到链表中。 2. 从第一个节点开始,依次遍历链表,每次遍历到第m个节点时,将该节点从链表中删除。 3. 继续从删除节点的下一个节点开始遍历,重复上述操作,直到链表中只剩下一个节点为止。 4. 最后剩下的那个节点就是最后出列的人,输出其编号即可。 下面是具体的代码实现: ```python class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next def josephus(n: int, m: int) -> int: # 创建循环链表 head = ListNode(1) cur = head for i in range(2, n+1): cur.next = ListNode(i) cur = cur.next cur.next = head cur = head while cur.next != cur: # 只有一个节点时停止遍历 # 找到第m个节点的前一个节点 for i in range(m-1): cur = cur.next print(cur.next.val, end=' ') # 输出删除的节点的值 cur.next = cur.next.next # 删除节点 cur = cur.next # 继续遍历链表 return cur.val # 返回最后剩下的那个节点的值 n = 10 m = 3 res = josephus(n, m) print("\nThe last one is:", res) ``` 在上述代码中,我们先创建一个循环链表,并从头节点开始遍历链表,每次遍历到第m个节点时,将该节点从链表中删除。最后只剩下一个节点时,返回该节点的值即可。 在遍历链表时,我们使用指针cur来指向当前节点,使用cur.next来访问下一个节点,使用cur.next.val来访问节点的值。在删除节点时,我们使用cur.next = cur.next.next来删除节点。 至此,我们就用约瑟夫问题为例,讲授了Python链表节点的访问与遍历。通过这个例子,我们可以更加深入地理解链表的基本概念和操作,并掌握如何用Python实现链表相关的算法和应用。
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值