六月集训(第13天)—双向链表

双向链表

1. 432. 全 O(1) 的数据结构

    思路:
        $O(1)$时间查询,则立刻想到hash表,这题又是双向链表专题的,于是想办法把双向链表和hash表结合起来。
        (1) 用双向链表存储键值为key的结点,只需要存一个,再次inc只需要将其对应的count值+1即可
        (2) hash表中将key映射到双向链表的结点地址,实现$O(1)$查询
        (3) 将双线链表按照每个结点的count值升序排列,设置head和tail指针,实现$O(1)$时间查询Max和Min
        (4) 每次inc或者del维护双向链表按照升序排列

struct BiNode {
    string key;
    int count;
    BiNode *prev, *next;

    BiNode() {
        prev = next = NULL;
    }
};

class AllOne {
    BiNode *head, *tail;
    unordered_map<string, BiNode*> hash;

    void swap(string &a, string &b) {
        string temp = a;
        a = b;
        b = temp;
    }

    void swap(int &a, int &b) {
        int temp = a;
        a = b;
        b = temp;
    }
public:
    AllOne() {
        head = tail = NULL;
        hash.clear();
    }
    
    void insert(BiNode *node) {
        if (head == NULL) {
            head = tail = node;
            return ;
        }
        // 链表头部插入一个结点
        head->prev = node;
        node->next = head;
        head = node;
    }

    void del(BiNode *node) {
        // 修改前一个点的后继
        if (node->prev) {
            node->prev->next = node->next;
        } else {
            head =node->next;   /* 更新头节点的位置 */
        }
        // 修改后一个点的前驱
        if (node->next) {
            node->next->prev = node->prev;
        } else {
            tail = node->prev;  /* 更新尾结点位置 */
        }
    }

    // 向后维持按照key的出现次数,升序排列
    void balance_backward(BiNode *node) {
        while (node && node->next) {
            if (node->count > node->next->count) {  /* 链表按照每个key的出现次数,升序排列 */
                BiNode *nnext = node->next;
                swap(node->key, nnext->key);
                swap(node->count, nnext->count);

                // 交换hash表中键值映射的结点
                BiNode *tmp = hash[node->key];
                hash[node->key] = hash[nnext->key];
                hash[nnext->key] = tmp;
            }
            node = node->next;
        }
    }

     // 向前维持按照key的出现次数,升序排列
    void balance_foward(BiNode *node) {
        while (node && node->prev) {
            if (node->count < node->prev->count) {
                BiNode *nprev = node->prev;
                swap(node->key, nprev->key);
                swap(node->count, nprev->count);

                BiNode *tmp = hash[node->key];
                hash[node->key] = hash[nprev->key];
                hash[nprev->key] = tmp;
            }
            node = node->prev;
        }
    }

    void inc(string key) {
        auto iter = hash.find(key);
        BiNode *node;
        if (iter == hash.end()) { // 如果该键值对应的结点不存在,则创建一个新结点
            node = new BiNode();
            node->key = key;
            node->count = 1;
            hash[key] = node;
            insert(node);
        } else {
            node = iter->second;
            node->count++;
        }
        balance_backward(node); // node->count变大了,将其向后维护升序排列
    }
    
    void dec(string key) {
        auto iter = hash.find(key);
        BiNode *node = iter->second;
        node->count--;
        if (node->count == 0) {
            del(node);
        } else {
            balance_foward(node);   // // node->count变小了,将其向前维护升序排列
        }
    }
    
    string getMaxKey() {
        if (tail == NULL) return "";
        return tail->key;
    }
    
    string getMinKey() {
        if (head == NULL) return "";
        return head->key;
    }
};

/**
 * Your AllOne object will be instantiated and called as such:
 * AllOne* obj = new AllOne();
 * obj->inc(key);
 * obj->dec(key);
 * string param_3 = obj->getMaxKey();
 * string param_4 = obj->getMinKey();
 */
posted @ 2022-06-13 08:21  番茄元  阅读(33)  评论(0)    收藏  举报