python实现双向链表以及双向循环链表

目录

双向链表

介绍:

链表功能:

说明:

talk is cheap,show me your code:

衍生双向循环链表

实现:

应用:

代码:


双向链表

介绍:

百度百科:双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表

链表功能:

尾插、尾删、指定位置插入指定值、删除指定位置节点、遍历、长度、反转、清空、删除倒数第n个节点

说明:

双向链表维护一个头节点、尾节点、链表长度,代码效率高

talk is cheap,show me your code:

bidirect.py:

class Node:
    '''
    链表节点
    previous <- node(value) -> next
    '''
    def __init__(self, val = None):
        self.value = val
        self.previous = None
        self.next = None


    def __del__(self):
        # print('delete the node')
        pass


class LinkList:
    '''
    双向链表,采用哨兵结构,头尾节点值为空
    head <-> node1 <-> node2 ...<-> node(n) <-> tail
    '''
    def __init__(self):
        self.head = Node()
        self.tail = Node()
        self.head.next = self.tail
        self.tail.previous = self.head
        self.length = 0


    def __len__(self) -> int:
        '''
        求链表长度
        :return: 返回链表长度
        '''
        return self.length


    def insert(self, pos = 0, val = 0):
        '''
        在链表指定位置插入指定值
        位置参数:param pos: 整型且大于等于零
        插入值参数:param val:
        :return: 布尔型
        '''
        if not (isinstance(pos, int) and pos >= 0 and pos <= self.length):
            raise Exception('输入的位置参数不合法')
        node = self.head
        i=0
        while node.next != self.tail:
            node = node.next
            if pos == i:
                new = Node(val)
                nodePre = node.previous
                nodePre.next = new
                new.previous = nodePre

                new.next = node
                node.previous = new

                self.length += 1
                return True
            i += 1
        else:
            if i == self.length:
                self.append(val)
                return True
            return False


    def pop(self):
        '''
        尾删
        :return: 返回被删节点的值
        '''
        if self.length == 0:
            raise Exception('链表已为空')
        tailPre = self.tail.previous
        val = tailPre.value
        tailPrePre = self.tail.previous.previous
        tailPrePre.next = self.tail
        self.tail.previous = tailPrePre
        del tailPre
        self.length -= 1
        return val


    def append(self, val):
        '''
        尾插
        '''
        tailPre = self.tail.previous
        new = Node(val)
        tailPre.next = new
        new.previous = tailPre
        new.next = self.tail
        self.tail.previous = new
        self.length += 1


    def remove(self, pos):
        '''
        删除链表指定位置节点
        :return: 返回被删除的值
        '''
        if self.length == 0:
            raise Exception('链表已为空')
        if not(isinstance(pos,int) and pos >= 0 and pos < self.length):
            raise Exception('输入的位置参数不合法')

        node = self.head
        i = 0
        while node.next != self.tail:
            node = node.next
            if pos == i:
                nodeNext, nodePre = node.next, node.previous
                val = node.value
                nodePre.next = nodeNext
                nodeNext.previous = nodePre
                del node
                self.length -= 1
                return val
            i += 1


    def traverse(self):
        '''
        遍历链表
        '''
        if self.length == 0:
            raise Exception('链表为空')
        node = self.head
        while node.next != self.tail:
            node = node.next
            print(node.value, end = ' ')
        print()


    def reverse(self):
        '''
        链表反转
        :return: 返回反转后的链表
        '''
        if self.length == 0:
            raise Exception('链表为空')
        node = self.tail
        newll = LinkList()
        while node.previous != self.head:
            node = node.previous
            newll.append(node.value)
        return newll

    
    def clear(self):
        '''
        清空链表(保留头节点和尾节点)
        '''
        self.head.next=self.tail
        self.tail.previous=self.head


    def remove_lastn(self,n):
        '''
        删除倒数第n个节点
        '''
        if not(isinstance(n,int) and n<=self.length and n>=1):
            raise Exception('输入参数n不合法')
        node=self.tail
        i=0
        while node.previous != self.head:
            node=node.previous
            i+=1
            if i==n:
                nodeNext=node.next
                nodePre=node.previous
                nodePre.next=nodeNext
                nodeNext.previous=nodePre


if __name__ == '__main__':
    ll = LinkList()
    print(ll.__doc__)
    ll.append(1)
    ll.append(2)
    ll.append(3)
    ll.append(4)
    ll.traverse()
    print(ll.head.next.value, ll.tail.previous.value)
    print(ll.pop())
    ll.traverse()
    ll.insert(0, 5)
    ll.insert(2, 4)
    print(ll.insert(5, 6))
    print('len=', len(ll))
    ll.traverse()
    print(ll.head.next.value, ll.tail.previous.value)
    ll = ll.reverse()
    ll.traverse()
    print(ll.head.next.value, ll.tail.previous.value)
    ll = ll.reverse()
    ll.traverse()
    print(ll.head.next.value, ll.tail.previous.value)

测试结果:

衍生双向循环链表

实现:

将尾节点指向头节点即可,此带有头尾节点的循环链表使用过程中需额外多加判断,但问题不大

应用:

约瑟夫环游戏(已知 n 个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围。从编号为 k 的人开始报数,数到 m 的那个人出圈;他的下一个人又从 1 开始报数,数到 m 的那个人又出圈;依此规律重复下去,直到剩余最后一个胜利者。)

代码:

from bidirect import *


class CircleLinkList(LinkList):
    '''
    循环链表
    '''
    def __init__(self):
        super().__init__()
        self.tail.next=self.head
        self.head.previous=self.tail


    def generate_withN(self,n):
        '''
        根据n生成节点为1-n的循环链表
        :param n:
        :return:
        '''
        self.length=0
        node=self.head
        for i in range(1,n+1):
            new=Node(i)
            node.next=new
            new.previous=node
            self.length+=1
            node=node.next
        new.next=self.tail
        self.tail.previous=new


def Joseph(n,k,m):
    '''
    约瑟夫环问题
    :param n: 人数
    :param k: 第k个人开始
    :param m: 报数到m
    :return: 最后一个人,胜利者
    '''
    if not(isinstance(n,int) and n>0 and isinstance(k,int) and 0<k<=n and isinstance(m,int) and m>0):
        raise Exception('input illegal')
    cll=CircleLinkList()
    cll.generate_withN(n)
    head=cll.head
    i=0
    while head.next!=cll.tail:
        head=head.next
        i+=1
        if i==k:
            break
    print('head:',head.value)
    node=head
    i=0
    while cll.length!=1:
        if node!=cll.tail and node!=cll.head:
            i+=1
        if i==m:
            i=0
            nodePre,nodeNext=node.previous,node.next
            nodePre.next=nodeNext
            nodeNext.previous=nodePre
            cll.length-=1
            cll.traverse()
        node=node.next
    return node.value


if __name__ == '__main__':
    ll = CircleLinkList()
    print(ll.__doc__)
    winner=Joseph(14,2,5)
    print('winner:',winner)

测试结果:

 

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
双向循环链表是一种链式数据结构,每个节点除了存储数据外,还有两个指针,分别指向前驱节点和后继节点。与单向链表相比,双向链表可以支持双向遍历和删除操作。 下面是用 Python 实现双向循环链表的代码: ```python class Node: def __init__(self, data): self.data = data self.prev = None self.next = None class DoublyLinkedList: def __init__(self): self.head = None def is_empty(self): return self.head is None def add_first(self, data): new_node = Node(data) if self.is_empty(): self.head = new_node new_node.prev = new_node new_node.next = new_node else: new_node.next = self.head new_node.prev = self.head.prev self.head.prev.next = new_node self.head.prev = new_node self.head = new_node def add_last(self, data): new_node = Node(data) if self.is_empty(): self.head = new_node new_node.prev = new_node new_node.next = new_node else: new_node.prev = self.head.prev new_node.next = self.head self.head.prev.next = new_node self.head.prev = new_node def remove_first(self): if self.is_empty(): return None elif self.head.next is self.head: data = self.head.data self.head = None return data else: data = self.head.data self.head.next.prev = self.head.prev self.head.prev.next = self.head.next self.head = self.head.next return data def remove_last(self): if self.is_empty(): return None elif self.head.next is self.head: data = self.head.data self.head = None return data else: data = self.head.prev.data self.head.prev.prev.next = self.head self.head.prev = self.head.prev.prev return data def __str__(self): if self.is_empty(): return '[]' else: s = '[' node = self.head while node.next is not self.head: s += str(node.data) + ', ' node = node.next s += str(node.data) + ']' return s ``` 以上是基础的双向循环链表实现,你可以根据自己的需求,添加其他方法和属性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值