关于Python实现树结构和链表结构的一点想法

关于Python实现树结构和链表结构的一点想法

Python由于内置的数据结构具有很高的灵活性,所以可以用很多种方式来构建树、图、链表等结构

1. 树的Python实现

  • python自然可以使用class来创建Node结点类和Trie类,然后通过left和right属性保存Node结点来实现树
  • Python也可以使用字典来嵌套生成树,字典的Key作为当前结点,字典的Value为子树。
  • 但需要注意的是,字典的value是一个字典,那么这个value字典中可以有多个Key,那么每个Key之间是互相为兄弟关系的。
  • 同理,如列表等数据结构,也可以通过嵌套来生成树
  • 在使用字典创建树时,可以重复利用dict的方法setdefault(key,default),如果key存在,则返回value,若不存在,则插入key:default并返回default

--------------------------

  • 比较有意思的是对于树而言,在哪里存他的数据会有很多的不同,对于不同场景酌情实现
  • 假设是使用class实现的字母前缀树,那么可以把字母值保存在当前Node结点的value中,那么这样匹配一个单词的时候,需要遍历所有的子节点找到对应值是否存在,这样在某一层上就多花了k的时间(由于字典自带哈希,所以字典实现的前缀树查找会很快,是O(1)的时间)
  • 也可以把字母值保存在连向子结点的连线上
  • 由于字母前缀树每个结点最多只有26种取值,所以可以提前存一个初始化为26个None的列表,如果在b的位置有值,那么在第二个位置存子结点的Node,这样就实现了把字母值存在连向子结点的连线上。
  • 同时,匹配一个单词的时候,直接来判断这个位置是None还是存在Node结点就可以直接找到下一个结点了,也是O(1)的时间,但是如果树很深,但是很窄的话,这样会浪费许多空间
  • 所以针对不同的场景需求,可以自行选择存储数据的位置,有不同的效果。

利用字典实现树代码如下

#利用字典实现前缀树
trie = {}
# 建立字典实现的字母前缀树
for word in words:
    cur = trie
    for alpha in word:
        cur=cur.setdefault(alpha,{})

2. 链表的Python实现

  • python本身的列表已经很好用了,在python的标准库中没有链接列表的实现,如果需要大量插入和删除还是需要手动实现一下的,可以实现O(k)的增删查找复杂度
  • 链表实现自然也可以用class来创建Node结点类和Trie类,在Trie类中创建head与tail的Node对象,就可以进行追踪了
  • 如果需要O(1)的查找以及增删复杂度的链表,那么需要配合哈希与双向链表实现、那么在Trie类中还需要添加一个dict哈希来进行节点位置的追踪,key为Node节点的Key(Node节点属性有Key、value、next、pre),Value为该Node节点
#配合哈希与双向链表实现O(1)的查找以及增删复杂度
class Node:
    def __init__(self,key,value):
        self.key=key
        self.value=value
        self.next=None
        self.pre=None

class LRUCache:

    def __init__(self, capacity: int):
        self.dic=dict()
        self.capacity=capacity
        self.size=0

        self.head=Node(-1,-1)
        self.tail=Node(-1,-1)

        self.head.next=self.tail
        self.tail.pre=self.head


    def get(self, key: int) -> int:
        if(key in self.dic):
            new_node = Node(key, self.dic[key].value)
            # 删除旧节点
            del_node = self.dic[key]
            del_node.pre.next = del_node.next
            del_node.next.pre = del_node.pre

            # 添加新节点到头部
            new_node.pre = self.head
            new_node.next = self.head.next
            self.head.next.pre = new_node
            self.head.next = new_node

            self.dic[key]=new_node

            return self.dic[key].value
        else:
            return -1

    def put(self, key: int, value: int) -> None:
        new_node = Node(key, value)

        # 添加新节点到头部
        new_node.pre = self.head
        new_node.next = self.head.next
        self.head.next.pre = new_node
        self.head.next = new_node


        if(key in self.dic):
            del_node=self.dic[key]
            del_node.pre.next=del_node.next
            del_node.next.pre=del_node.pre
        else:
            # 如果key不在链表中,才考虑删去尾元素或者更改size
            if(self.size==self.capacity):
                # 如果满了,要删去尾部节点
                self.dic.pop(self.tail.pre.key)
                self.tail.pre.pre.next=self.tail
                self.tail.pre=self.tail.pre.pre
            else:
                self.size+=1

        self.dic[key] = new_node

posted @ 2020-10-18 21:36  阿杰也请你吃颗糖  阅读(405)  评论(0编辑  收藏  举报