链表的python实现

一、单向链表

        链表是由一系列节点组成的元素集合,每个节点包含两部分,数据域item和指向下一个节点的指针next,通过节点之间的相互连接,形成链表。

1、节点定义

class Node:
    def __init__(self, item):
        self.item = item  # 存放节点数据
        self.next = None  # 用于指向下一个节点

2、创建链表

       头插法

往链表的前面插入元素,插入元素的节点链向原来的头结点,让插入的元素成为新的头节点。

def create_linklist_head(li):   # li为列表
    head = Node(li[0])  # 先让列表中的第一个元素成为头结点
    for element in li[1:]:   # 往后遍历列表
        node = Node(element)
        node.next = head
        head = node
    return head   # 返回头结点,用于实现链表打印
        尾插法

往链表后面插入元素,原尾节点链向插入元素,插入元素成为新的尾节点。(注意构造时开始要让头结点和尾节点指向同一个位置)

def create_linklist_tail(li):   # li为列表
    head = Node(li[0])   # 构造头节点
    tail = head  # 尾节点和头结点指向同一个位置
    for element in li[1:]:
        node = Node(element)
        tail.next = node
        tail = node
    return head  # 返回头结点用于实现链表的打印

3、链表节点的插入

        先找到要插入位置的前面的节点(curnode),curnode.next 表示要插入位置的后面的节点,p表示要插入的节点,可以执行操作 :   

 p.next = curNode.next
 curNode.next = p

# 插入元素
def linklist_insert(curNode, node, element):   # curNode为插入元素的前一个元素,element为要插入的元素
    p = Node(element)
    while curNode:  # 找到要插入的位置   
        if curNode.item == node:
            # 节点插入执行的操作
            p.next = curNode.next
            curNode.next = p
            return
        curNode = curNode.next
    raise ValueError("There is no such element")

4、链表节点的删除

        首先找到要删除节点的前一个节点(curnode),所以curnode.next 表示要删除的节点,在执行删除操作:curnode.next = curnode.next.next
                      del p

前一个节点直接跳过删除节点,链向要删除节点的后一个节点。

# 删除元素
def linklist_delete(curnode, node):  # curnode为传进去的头结点,node是要删除的节点的元素

    while curnode:  # 寻找删除节点的位置
        p = curnode.next  # p为要删除的节点
        if curnode.next.item == node:
            if curnode.next.next == None:   # 如果要删除的节点是尾节点
                curnode.next = None
                return
            else:  # 删除的节点为中间节点
                # 删除执行的操作
                curnode.next = curnode.next.next
                del p
                return
        curnode = curnode.next

5、链表打印

def print_linklist(node):  # 输入头结点
    while node:  # 遍历链表
        print(node.item, end=" ")
        node = node.next

6、单向链表封装到类


class Node:
    def __init__(self, item):
        self.item = item
        self.next = None


class Linkedlist:
    def __init__(self):
        self.head = None
        self.tail = None

    def create_linklist_head(self, item):  # 头插法  可以向前插入单个元素
        node = Node(item)  # 创建Node对象
        if not self.head:
            self.head = node
            self.tail = self.head
        else:
            node.next = self.head  # 将存入的元素指向头元素
            self.head = node  # 让新存入的元素成为头元素

    def linklist_head_insert(self, li):   # 使用头插法,批量插入列表数据
        if not self.head:
            self.head = Node(li[0])  # 创建Node对象,成为头元素
            for element in li[1:]:  # 遍历从下标1开始的列表,将所有元素存入链表
                self.create_linklist_head(element)
        else:
            for element in li:  # 遍历从下标1开始的列表,将所有元素存入链表
                self.create_linklist_head(element)

    def create_linklist_tail(self, item):  # 尾插法  可以插入单个元素
        node = Node(item)  # 创建Node对象
        if not self.head:
            self.head = node
            self.tail = self.head
        else:
            self.tail.next = node  # 尾链接新元素
            self.tail = node  # 让新元素成为新的尾

    def linklist_tail_insert(self, li):   # 使用尾插法,批量插入列表数据
        if not self.head:
            self.head = Node(li[0])    # 头结点指向列表第一个元素
            self.tail = self.head    # 刚开始头结点与尾节点一致
            # self.tail = Node(li[0])
            # 问题:只有self.tail = Node(li[0])时,从head开始遍历链表没有输出,从tail开始遍历链表只会输出第一个元素
            # 1:self.tail = Node(li[0])表示创建了一个新的Node对象,难道是因为没有设置头结点的原因吗?
            # 2:self.tail = self.head 表示将尾节点设置为与头节点相同的引用
            # 我懂了,在这个链表中遍历是向后遍历的,而尾节点指向None,所以只能打印最后一个元素
            # 只有self.tail = Node(li[0])时,链表没有指定头元素,所以从head遍历没有输出
            for element in li[1:]:  # 遍历从下标1开始的列表,将所有元素存入链表
                self.create_linklist_tail(element)
        else:
            for element in li:  # 遍历从下标1开始的列表,将所有元素存入链表
                self.create_linklist_tail(element)

    # 链表节点的插入
    def linklist_insert(self, node, data):  # node是要插入的位置(在哪个元素后面插入),data是要插入的数据
        curnode = self.head   # 指向头结点
        while curnode:   # 循环链表
            if curnode.item == node:   # 找到位置
                # 执行插入元素操作
                newnode = Node(data)   # 生成Node对象
                newnode.next = curnode.next   # 插入元素向后指向后一个元素
                curnode.next = newnode   # 前一个元素向后指向插入的元素
                break
            else:
                curnode = curnode.next  # 进入下一个节点

    # 链表节点的删除
    def linklist_del(self, data):
        curnode = self.head
        p = None
        while curnode:
            if curnode.item != data:
                p = curnode   # p表要删除元素的前一个元素示
                curnode = curnode.next
            else:   # 找到了要删除的元素
                p.next = p.next.next    # 要删除元素的前一个元素向后指向要删除元素的下一个元素
                curnode = curnode.next  # 进入下一个节点
        del p

    # 链表输出
    def print_linklist(self):
        curnode = self.head
        while curnode:
            print(curnode.item, end=',')
            curnode = curnode.next  # 进入下一个节点


ll = Linkedlist()

ll.create_linklist_head(3)
ll.create_linklist_head(9)
ll.print_linklist()

二、双向链表

1、节点定义

        双链表是在链表的基础上,每个节点有两个指针:一个指向前一个节点,一个指向后一个节点。

class Node:
    def __init__(self, item):
        self.item = item    # 用于存放节点数据
        self.prior = None   # 指向前一个节点
        self.next = None   # 指向后一个节点

2、创建双链表

        头插法

        在单链表头插法的基础上加一个向前指针,原来头结点的向前指针指向插入节点,插入节点的向后指针指向头结点,再使插入的节点成为新的头结点。

# 头插法
def create_double_linklist_head(li):   # li为列表
    head = Node(li[0])
    tail = head
    for element in li[1:]:
        node = Node(element)
        # 执行插入操作
        head.prior = node
        node.next = head
        head = node

    return head  # 返回头结点,以便遍历链表
        尾插法

        同理,在单链表的基础上加一个向前指针,原尾节点的向后指针指向插入节点,插入节点的向前指针指向原尾节点,再让插入元素成为新的尾节点。

# 尾插法
def create_double_linklist_tail(li):  # li为要构建链表的列表
    head = Node(li[0])
    tail = head
    for element in li[1:]:
        node = Node(element)
        # 插入操作
        tail.next = node
        node.prior = tail
        tail = node

    return head   # 同样返回头节点,以便打印链表

3、链表节点的插入

        类比单链表插入,先找到要插入位置的前一个节点(curnode),curnode.next 表示要插入位置的后一个节点,执行操作:p.next = curnode.next

                                               curnode.next.prior = p

                                               p.prior = curnode

                                               curnode.next = p

# 中间节点的插入
def double_linklist_insert(head, node, element):   # head是头结点,curnode为插入位置的前一个节点的元素,element为要插入的元素
    curnode = head
    p = Node(element)  # 创建要插入的节点
    while curnode:
        if curnode.item == node:
            p.next = curnode.next
            curnode.next.prior = p
            p.prior = curnode
            curnode.next = p
            return
        curnode = curnode.next

4、链表节点的删除

        同上述先找节点,把要删除节点的前一个节点跳过要删除节点向后指向删除节点的后一个节点,后一个节点同理跳过删除节点指向后一个节点,执行操作:

        p = curnode.next

        curnode.next = p.next

        p.next.prior = curnode

        del p

def double_linklist_delete(head, node):
    curnode = head
    while curnode:
        p = curnode.next
        if p.item == node:
            curnode.next = p.next
            p.next.prior = curnode
            del p
            return
        curnode = curnode.next

5、打印链表

def print_double_linklist(node):  # 输入头结点
    while node:  # 遍历链表
        print(node.item, end=" ")
        node = node.next

6、双链表封装到类

# 建立双链表
class Node:
    def __init__(self, item=None):
        self.item = item  # 元素
        self.next = None   # 向后指针
        self.prior = None   # 向前指针

class Doublelinklist:
    def __init__(self):
        self.head = None
        self.tail = None

    def create_linklist_head(self, item):  # 头插法  可以插入单个元素
        node = Node(item)  # 把元素存入链表
        node.next = self.head  # 将存入的元素通过链表向后指针指向头元素
        self.head.prior = node
        self.head = node  # 让新存入的元素成为头元素

    def linklist_head_insert(self, li):   # 使用头插法,批量插入列表数据
        self.head = Node(li[0])
        for element in li[1:]:  # 遍历从下标1开始的列表,将所有元素存入链表
            self.create_linklist_head(element)

    def create_linklist_tail(self, item):  # 尾插法  可以向后插入单个元素
        node = Node(item)  # 把元素存入链表
        self.tail.next = node  # 尾链接新元素
        node.prior = self.tail
        self.tail = node  # 让新元素成为新的尾

    def linklist_tail_insert(self, li):  # 使用尾插法,批量插入列表数据
        self.head = Node(li[0])  # 头结点指向列表第一个元素
        self.tail = self.head  # 刚开始头结点与尾节点一致
        for element in li[1:]:  # 遍历从下标1开始的列表,将所有元素存入链表
            self.create_linklist_tail(element)

    # 链表节点的插入
    def linklist_insert(self, node, data):  # node是要插入的位置(在哪个元素后面插入),data是要插入的数据
        curnode = self.head   # 指向头结点
        while curnode:   # 循环链表
            if curnode.item == node:   # 找到位置
                # 执行插入元素操作
                newnode = Node(data)
                newnode.next = curnode.next  # 插入元素向后指向下一个元素
                curnode.next.prior = newnode  # 下一个元素向前指向插入的元素
                newnode.prior = curnode   # 插入元素向前指向前一个元素
                curnode.next = newnode   # 前一个元素向后指向插入的元素
                break
            else:
                curnode = curnode.next   # 进入下一个节点,继续遍历

    # 链表节点的删除
    def linklist_del(self, data):
        curnode = self.head
        p = None
        while curnode:
            if curnode.item != data:
                p = curnode   # p表要删除元素的前一个元素
                curnode = curnode.next
            else:  # 找到了要删除的元素
                delnode = p.next   # 表示要删除的元素
                p.next = delnode.next   # 要删除元素的前一个元素向后指向要删除元素的后一个元素
                delnode.next.prior = p   # 要删除元素的后一个元素向前指向要删除元素的前一个元素
                curnode = curnode.next    # 进入下一个节点,继续遍历
        del p

    def print_linklist(self):
        curnode = self.head
        while curnode:
            print(curnode.item, end=',')
            curnode = curnode.next  # 进入下一个节点

dll = Doublelinklist()
dll.linklist_tail_insert([1, 3, 2, 5, 4, 7, 6])
# dll.linklist_head_insert([1, 3, 2, 5, 4, 7, 6])
dll.linklist_insert(4, 9)
dll.linklist_del(5)
dll.print_linklist()

  • 18
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值