zoukankan      html  css  js  c++  java
  • 双向链表

    链表是实现了数据之间保持逻辑顺序,但存储空间不连续的数据结构。
    相对于单向链表,双向链表多了一个指向前面一个节点的指针域。
    链表查询效率较慢,因为查询的时候需要移动指针一个一个找。
    双向链表新增和删除元素效率较高,因为链表会记录前一个节点和后一个节点。

    class Node:
        def __init__(self, item, next=None, prev=None):
            self.item = item
            self.next = next
            self.prev = prev
    
        def __str__(self):
            return '<prev: {} <- node: {} -> next: {}>'.format(self.prev.item if self.prev else None, self.item, self.next.item if self.next else None)
    
        def __repr__(self):
            return str(self.item)
    
    class LinkedList:
        def __init__(self):
            self.head = None
            self.tail = None
            self.size = 0
    
        def append(self, item):
            node = Node(item)
            # 如果head节点为空,表示链表为空
            if self.head is None:
                self.head = node
                self.tail = node
            else:
                self.tail.next = node
                node.prev = self.tail
                self.tail = node
            self.size += 1
            return self
    
        def index(self, item):
            for i, node in enumerate(self):
                if item == node.item:
                    return i
            else:
                raise ValueError('item does not exist')
    
        def insert(self, index, item):
            if index < 0:
                raise IndexError
    
            # 如果找到就将current指向对应位置的节点,继续后面的操作
            # 如果没有找到(链表为空或者索引超界),则追加并立即返回,后面的操作将不会执行
            for i, node in enumerate(self):
                if i == index:
                    current = node
                    break
            else:
                self.append(item)
                return
    
            node = Node(item)
            prev = current.prev
    
            # 从头部插入
            if prev is None:
                node.next = current
                current.prev = node
                self.head = node
            # 从中间插入(尾部插入即追加,上面已经实现)
            else:
                node.next = current
                node.prev = prev
                prev.next = node
                current.prev = node
    
            self.size += 1
    
        def pop(self):
            # 如果尾部为空,则表示链表为空
            if self.tail is None:
                raise Exception('empty')
    
            node = self.tail
            item = node.item
            prev = node.prev
    
            # 如果尾部节点没有前节点,则表示链表只有一个元素
            if prev is None:
                self.head = None
                self.tail = None
            # 剩下就是有多个节点的情况
            else:
                prev.next = None
                self.tail = prev
    
            self.size -= 1
            return item
    
        def remove(self, index):
            if index < 0:
                raise IndexError('does not support negative index')
    
            # 如果链表为空,则抛出异常
            if self.head is None:
                raise Exception('empty')
    
            # 如果找到就将current指向对应位置的节点,继续后面的操作
            # 如果没有找到(链表为空或者索引超界),则抛出异常
            for i, node in enumerate(self):
                if i == index:
                    current = node
                    break
            else:
                raise IndexError('index out of range')
    
            prev = current.prev
            next = current.next
    
            # 如果current没有前节点也没有后节点,表示只有一个节点
            if prev is None and next is None:
                self.head = None
                self.tail = None
            # 如果不止一个节点,且如果current没有前节点,表示current是head
            elif prev is None:
                next.prev = None
                self.head = next
            # 如果不止一个节点、current不是head,且如果current没有后节点,表示current是tail
            elif next is None:
                prev.next = None
                self.tail = prev
            # 剩下就是多节点从中间remove的情况
            else:
                prev.next = next
                next.prev = prev
    
            self.size -= 1
    
        # def iternodes(self, reverse=False):
        #     current = self.head if not reverse else self.tail
        #     while current:
        #         yield current
        #         current = current.next if not reverse else current.head
    
        def clear(self):
            for node in self:
                node.prev = None
                node.tail = None
            self.head = None
            self.tail = None
            self.size = 0
    
        def __iter__(self):
            current = self.head
            while current:
                yield current
                current = current.next
    
        def __reversed__(self):
            current = self.tail
            while current:
                yield current
                current = current.prev
    
        def __len__(self):
            # current = self.head
            # count = 0
            # while current:
            #     count += 1
            #     current = current.next
            # return count
            return self.size
    
        def __getitem__(self, key):
            # 支持负索引
            obj = reversed(self) if key < 0 else self
            start = 1 if key < 0 else 0
    
            for i, node in enumerate(obj, start):
                if abs(key) == i:
                    return node
            else:
                raise IndexError('index out of range')
    
        def __setitem__(self, key, value):
            # for i, node in enumerate(self):
            #     if key == i:
            #         node.item = value
            # else:
            #     self.append(value)
            self[key].item = value
    
    
    linklist = LinkedList()
    
    # 测试append()
    for i in range(10):
        linklist.append(i)
    
    # 测试__iter__
    for node in linklist:
        print(node)
    
    # 测试__reversed__
    for node in reversed(linklist):
        print(node)
    
    # 测试__len__
    print(len(linklist))
    
    # 测试index()
    print(linklist.index(3))
    
    # 测试insert()
    linklist.insert(0, 0)
    print(list(linklist))
    
    # 测试pop()
    print(linklist.pop())
    
    # 测试__getitem__
    print(linklist[3])
    # print(linklist[13])
    print(linklist[-1])
    
    # 测试__setitem__
    linklist[5] = 15
    print(list(linklist))
    
    # 测试clear()
    linklist.clear()
    print(list(linklist))
    print(len(linklist))
    

    参考:
    http://zhaochj.github.io/2016/05/12/2016-05-12-数据结构-链表/
    https://blog.csdn.net/qq_26118603/article/details/79039738
    http://blog.suchasplus.com/2011/03/why-python-Standard-library-does-not-implement-the-list.html
    https://www.zhihu.com/question/55721190

  • 相关阅读:
    bzoj1015星球大战(并查集+离线)
    bzoj1085骑士精神(搜索)
    bzoj1051受欢迎的牛(Tarjan)
    左偏树学习
    hdu1512 Monkey King(并查集,左偏堆)
    左偏树(模板)
    PAT (Basic Level) Practice (中文) 1079 延迟的回文数 (20分) (大数加法)
    PAT (Basic Level) Practice (中文) 1078 字符串压缩与解压 (20分) (字符转数字——栈存放)
    PAT (Basic Level) Practice (中文) 1077 互评成绩计算 (20分) (四舍五入保留整数)
    PAT (Basic Level) Practice (中文) 1076 Wifi密码 (15分)
  • 原文地址:https://www.cnblogs.com/keithtt/p/9711039.html
Copyright © 2011-2022 走看看