怎么用python实现一个单链表

分析Q&A

Q: 链表的基本单位是啥?

A: 是结点(Node)

Q: 结点是怎样构成的?

A: 结点由2部分构成, 数据(data)和指向下一个结点的指针(next)

Q: 链表中特殊的结点是啥?

A: 是头结点(head), 作为起始结点, 没有头结点则为空链表(线性表允许有0个元素)

拆解代码

1. 首先定义结点

# 链表的基本单位--结点
class Node(object):
    def __init__(self, data):
        self.data = data  # 结点的元素值
        self.next = None  # 表示下一个结点的链接

2. 定义单向链表

2.1 初始化__init__

作为判断是否为空链表的依据, 必须把头结点定义出来, 可以给个缺省参数None

# 链表
class LinkedList(object):
    # 初始化链表
    def __init__(self, head=None):
        self.head = head  # 链表的头结点

2.2 添加/追加新结点(链表的新增)

2.2.1 首先把游标指向头结点, 如果头结点不存在, 那就把新插入的结点设置为头结点;
2.2.2 如果头结点存在, 但是next指针指向None, 也就是说链表有且仅有头结点1个结点, 那么直接把next指针指向新结点即可;
2.2.3 如果头结点存在, 而且next指针指向了下一个结点, 那么把游标移动到下一个结点处, 直到游标所在的结点是链表的尾部结点(next–>None), 把尾部结点的next指向新结点

    # 追加新结点
    def append(self, new_element):
        """在链表的尾部追加新的元素"""
        # 首先把头结点设为当前结点
        current = self.head
        # 如果头结点存在
        if self.head:
            # 如果头结点有链接
            while current.next:
                # 把链接的结点设置为当前结点, 继续循环
                # 直到当前结点为链表的最后一个结点
                current = current.next
            # 头结点没有链接, 新元素作为头结点的链接
            current.next = new_element
        # 如果头结点不存在
        else:
            # 把新结点设置为头结点
            self.head = new_element

2.3 判断链表是否为空

很简单, 只需要判断头结点是否存在即可

    # 判断链表是否为空链表
    def is_empty(self):
        return not self.head

2.4 获取链表的长度

先定义一个游标, 指向头结点, 初始化长度为0, 如果游标所在结点存在, 那么长度+1, 游标指向下一个结点, 直到游标指向None, 说明到了尾部结点, 此时已累加的长度就是链表长度

    # 获取链表长度
    def get_length(self):
        temp = self.head
        length = 0
        # 循环到尾部结点,next=None
        while temp is not None:
            length = length + 1
            temp = temp.next
        return length

2.5 在任意位置插入结点

2.5.1 首先考虑的是下标越界的问题, 下标小于0或大于链表长度时, 下标越界; 解释一下为啥不是长度-1呢? 因为任意位置也包括最后, 那么position自然是尾结点链表+1, 也就是长度的数值;
2.5.2 如果插入位置是0, 相当于把新结点的next指向老的头结点, 同时把新结点设置为新的头结点;
2.5.3 在其他位置插入的话, 从head开始遍历到指定位置前一个位置, 并把前一位置的next指向新结点, 同时把新结点的next指向原来在该位置上的结点, 完成插入

    # 插入结点
    def insert(self, position, new_element):
        """在链表的指定索引处插入元素"""
        # 判断下标是否越界
        if position < 0 or position > self.get_length():
            raise IndexError("插入操作超出索引范围")
        temp = self.head
        # 在头结点处插入
        if position == 0:
            new_element.next = temp
            self.head = new_element
            return
        # 找到指定position处插入
        i = 0
        while i < position:
            pre = temp
            temp = temp.next
            i += 1
        pre.next = new_element
        new_element.next = temp

2.6 删除结点

2.6.1 依然要考虑下标越界问题, 注意此时的此时的上界就不是长度而是长度-1了;
2.6.2 删除头结点时, 把老的头结点后边的结点设置为新的头结点, 再把旧的头结点next指向None, 踢出链表
2.6.3 删除其他结点时, 先遍历找到到指定位置, 把指定位置前一个结点next指向指定位置后一个结点, 再把指定位置的结点的next指向None, 踢出链表

    # 删除结点
    def remove(self, position):
        """从任意位置删除一个元素"""
        # 判断下标是否越界
        if position < 0 or position > self.get_length() - 1:
            raise IndexError("删除操作超出索引范围")
        # 判断是不是空链表
        i = 0
        temp = self.head
        while temp is not None:
            # 删除头结点
            if position == 0:
                # 新的头结点=旧的头结点的next结点
                self.head = temp.next
                # 旧的头结点指向None, 没有前驱也没有后继, 相当于踢出链表
                temp.next = None

            pre = temp
            # 遍历链表
            temp = temp.next
            i += 1
            if i == position:
                # temp的前一个结点直接指向temp的后一个结点
                pre.next = temp.next
                # temp也不再指向后一个结点, 而指向None
                temp.next = None
                return

2.7 打印链表

从头结点开始获取结点中的data值, 打印出来即可

    # 打印链表
    def print_list(self):
        print('Linked List:')
        temp = self.head
        while temp is not None:
            print(temp.data)
            temp = temp.next

2.8 倒置链表

2.8.1 首先游标指向头结点
2.8.2 把头结点next指向None, 让头结点下一个结点指向头结点, 相当把头结点变成了尾结点, 并颠倒了其他所有指针的指向, 完成倒置

    # 倒置链表
    def reverse(self):
        """将链表反转过来"""
        prev = None
        current = self.head
        # 头结点指向None, 变成尾结点
        # 第二个结点指向头结点, 以此类推
        while current:
            next_node = current.next
            current.next = prev  # None, 旧的第二结点, 旧的第三结点...
            prev = current
            current = next_node
        # 最后遍历的结点(原来的尾结点)设置为头结点
        self.head = prev

2.9 把列表(顺序表)转换成链表

2.9.1 首先构造头结点, 把列表的0号元素, 实例化为Node, 并指定为链表的头结点
2.9.2 从第二个元素, 也就是下标1开始遍历列表, 不断把列表元素实例化为结点, 同时上一个结点的指针指向当前结点

    # 把普通列表转成链表
    def init_list(self, data_list):
        """把传入的list转换成链表"""
        # 调用Node, 把传入列表的第1个元素实例化为链表的头结点
        self.head = Node(data_list[0])
        temp = self.head
        # 从第二个元素开始遍历
        for i in data_list[1:]:
            node = Node(i)
            # 上一个结点指向当前结点
            temp.next = node
            # 把当前结点设置为temp
            temp = temp.next

你可能感兴趣的:(数据结构)