zoukankan      html  css  js  c++  java
  • 异或链表(XOR linked list)

    异或链表(Xor Linked List)也是一种链式存储结构,它可以降低空间复杂度达到和双向链表一样目的,任何一个节点可以方便的访问它的前驱节点和后继结点。可以参阅wiki

    普通的双向链表

    class Node {
    public:
        int data;
        Node *prev;
        Node *next;     
    };
    
    class BiLinkedList {
    public:
        Node *head;
        Node *tail;
    };
    普通双向链表的一个节点表示如下:
    image
    完整的普通双向链表如下所示:
    image
     

    对于异或链表来说,只是用一个xorPtr指针取代prev和next两个指针,这对于空间效率是一个提升。

    template<typename ElemType>
    class XorNode {
    public:
        ElemType data;
        XorNode<ElemType> *xorPtr;
        XorNode(ElemType data):data(data) { }
    };
    
    template<typename ElemType>
    class XorLinkedList {
    public:
        XorNode<ElemType> *head;
        XorNode<ElemType> *tail;
    }

    异或链表如下图所示,每一个Node记录data数据和xorPtr异或指针,异或指针记录前后两个指针的地址值的异或值

    image

    B的异或指针如下构造

    B->xorPtr = addr(A) ⊕ addr(C)

    获取B的前驱A的地址

    addr(A) = B->xorPtr ⊕ addr(C)

    获取B的后继C的地址

    addr(C) = B->xorPtr ⊕ addr(A)

    通过以上的几种操作,就可以遍历整个链表,在处理添加、插入、删除等操作时同普通的双向链表类似,在纸上多画画之间的关系就OK。

    记得处理边界,比如只剩一个节点进行删除操作时候,要判断前继和后驱Node是否为NULL,操作前要进行链表是否为空和越界的判断,xor是关键字。

    另外,B的xorPtr也可以类似的使用加法运算A+C, 假设B的指针是ptr,B的前驱为B->ptr – C, B的后继为B->ptr-A。

    指针转换为无符号整形,然后进行异或操作。

    这些异或和加法相关的操作都是针对指针值的本身,即指针转换为无符号整型数的结构,不能跟指针的运算操作混淆。

    下面就是完整的代码。

    #include <bits/stdc++.h>
    using namespace std;
    #define ERROR -1
    
    // XorNode Class
    template<typename ElemType>
    class XorNode {
    public:
        ElemType data;
        XorNode<ElemType> *xorPtr;
        XorNode(ElemType data):data(data) { }
    };
    
    // XorLinkedList Class
    template<typename ElemType>
    class XorLinkedList {
    public:
        XorNode<ElemType> *head;
        XorNode<ElemType> *tail;
        int size;
    
        // constructor function
        XorLinkedList() {
            head = NULL;
            tail = NULL;
            size = 0;
        }
    
        // is xorlinkedlist empty
        bool isEmpty() {
            return head == NULL && tail == NULL;
        }
    
        // xorlinkedlist length
        int length() {
            return size;
        }
    
        // add element into back
        void addBack(ElemType e) {
            XorNode<ElemType> *newNode = new XorNode<ElemType>(e);
            if (isEmpty()) {
                newNode->xorPtr = xor_func(NULL, NULL);
                head = newNode;
                tail = newNode;
            } else {
                newNode->xorPtr = xor_func(tail, NULL);
                tail->xorPtr = xor_func(xor_func(tail->xorPtr, NULL), newNode);
                tail = newNode;
            }
            size++;
        }
        
        //add element into front
        void addFront(ElemType e) {
            XorNode<ElemType> *newNode = new XorNode<ElemType>(e);
            if (isEmpty()) {
                newNode->xorPtr = xor_func(NULL, NULL);
                head = newNode;
                tail = newNode;
            } else {
                newNode->xorPtr = xor_func(NULL, head);
                head->xorPtr = xor_func(newNode, xor_func(head->xorPtr, NULL));
                head = newNode;
            }
            size++;
        }
    
        // pop element from back
        ElemType popBack() {
            if (isEmpty()) {
                cout << "XorLinkedList is empty." << endl;
                return ERROR;
            }
            XorNode<ElemType> *tmpNode = tail;
            ElemType ret = tail->data;
    
            tail = xor_func(tail->xorPtr, NULL);
            if (tail) tail->xorPtr = xor_func(xor_func(tail->xorPtr, tmpNode), NULL);
            else head = NULL;
            delete[] tmpNode;
            size--;
            return ret;
        }
    
        // pop element from front
        ElemType popFront() {
            if (isEmpty()) {
                cout << "XorLinkedList is empty." << endl;
                return ERROR;
            }
            XorNode<ElemType> *tmpNode = head;
            ElemType ret = head->data;
            head = xor_func(NULL, head->xorPtr);
            // if not pop last node, set the xorPtr
            if (head)  head->xorPtr = xor_func(NULL, xor_func(head->xorPtr, tmpNode));
            else tail = NULL;
            delete[] tmpNode;
            size--;
            return ret;
        }
    
        // return the value of pos
        ElemType getValue(int pos) {
            if (pos < 0 || pos >= length()) {
                cout << "pos ranges from " << 0 << " to " << length() - 1 << endl;
                return ERROR;
            }
            int step = 0;
            XorNode<ElemType> *curNode = NULL;
            if (pos <= length()/2) {
                curNode = head;
                step = pos;
            } else {
                curNode = tail;
                step = length() - pos - 1;
            }
            int i = 0;
            XorNode<ElemType> *otherNode = NULL, *tmpNode = NULL;
            while (i < step && curNode != NULL) {
                tmpNode = curNode;
                curNode = xor_func(curNode->xorPtr, otherNode);
                otherNode = tmpNode;
                i++;
            }
            return curNode->data;
        }
    
        // insert a node before pos
        void insert(ElemType e, int pos) {
            if (pos < 0 || pos > length()) {
                cout << "pos ranges from " << 0 << " to " << length() << endl;
                cout << "0: add element in front, " << length() << ": add element in back." << endl;
                return;
            }
            // deal with front and back
            if (pos == 0) addFront(e);
            else if(pos == length()) addBack(e);
            else {
                XorNode<ElemType> *curNode = NULL, *tmpNode = NULL, *otherNode = NULL;
                int i = 0;
                curNode = head;
                // find the pos
                while (i < pos && curNode != NULL) {
                    tmpNode = curNode;
                    curNode = xor_func(curNode->xorPtr, otherNode);
                    otherNode = tmpNode;
                    i++;
                }
                // insert the newNode before pos
                XorNode<ElemType> *newNode = new XorNode<ElemType>(e);
                newNode->xorPtr = xor_func(curNode, otherNode);
                otherNode->xorPtr = xor_func(xor_func(otherNode->xorPtr, curNode), newNode);
                curNode->xorPtr = xor_func(newNode, xor_func(otherNode, curNode->xorPtr));
                size++;
            }
        }
    
        // delete the element at pos
        void remove(int pos) {
            if (isEmpty()) {
                cout << "XorLinkedList is empty" << endl;
                return;
            }
            if (pos < 0 || pos >= length()) {
                cout << "pos ranges from " << 0 << " to " << length()-1 << endl;
                return;
            }
            if (pos == 0) popFront();
            else if (pos == length()) popBack();
            else {
                int step = 0;
                XorNode<ElemType> *curNode = NULL;
                if (pos <= length()/2) {
                    curNode = head;
                    step = pos;
                } else {
                    curNode = tail;
                    step = length() - pos - 1;
                }
                int i = 0;
                XorNode<ElemType> *otherNode = NULL, *tmpNode = NULL, *nextNode = NULL;
                while (i < step && curNode != NULL) {
                    tmpNode = curNode;
                    curNode = xor_func(curNode->xorPtr, otherNode);
                    otherNode = tmpNode;
                    i++;
                }
                nextNode = xor_func(curNode->xorPtr, otherNode);
                if (otherNode) otherNode->xorPtr = xor_func(xor_func(otherNode->xorPtr, curNode), nextNode);
                if (nextNode)  nextNode->xorPtr = xor_func(otherNode, xor_func(nextNode->xorPtr, curNode));
                delete[] curNode;
                size--;
            }
    
        }
    
        // traverse the xorlinkedlist.
        // f: head -> tail
        // r: tail -> head
        void traverse(char direction = 'f') {
            if (isEmpty()) {
                cout << "XorLinkedList is empty" << endl;
                return;
            }
    
            if (direction != 'f' && direction != 'r')  {
                cout << "direction error, 'f' or 'r'." << endl;
                return;
            }
    
            XorNode<ElemType> *curNode = NULL, *otherNode = NULL, *tmpNode = NULL;
            if (direction == 'f') curNode = head; // head -> tail
            else if (direction == 'r') curNode = tail;    // tail -> head
            do {
                cout << curNode->data << " ";
                tmpNode = curNode;
                curNode = xor_func(curNode->xorPtr, otherNode);
                otherNode = tmpNode;
            } while (curNode != NULL);
            cout << endl;
        }
    
    
    private:
        XorNode<ElemType>* xor_func(XorNode<ElemType> *a, XorNode<ElemType> *b) {
            return (XorNode<ElemType>*)((unsigned long)(a) ^ (unsigned long)(b));    
        }
    };
    
    
    int main() {
        XorLinkedList<int> xll;
        xll.insert(1,0);
        xll.insert(2,1);
        xll.insert(3,1);
        xll.traverse('f');
        // for (int i = 0; i < 3; i++)
        //     cout << xll.popBack() << endl; 
        xll.remove(1);
        xll.traverse('f');
        cout << endl;
        return 0;
    }
  • 相关阅读:
    BZOJ 1977: [BeiJing2010组队]次小生成树 Tree( MST + 树链剖分 + RMQ )
    BZOJ 2134: 单选错位( 期望 )
    BZOJ 1030: [JSOI2007]文本生成器( AC自动机 + dp )
    BZOJ 2599: [IOI2011]Race( 点分治 )
    BZOJ 3238: [Ahoi2013]差异( 后缀数组 + 单调栈 )
    ZOJ3732 Graph Reconstruction Havel-Hakimi定理
    HDU5653 Bomber Man wants to bomb an Array 简单DP
    HDU 5651 xiaoxin juju needs help 水题一发
    HDU 5652 India and China Origins 并查集
    HDU4725 The Shortest Path in Nya Graph dij
  • 原文地址:https://www.cnblogs.com/tiny656/p/4108976.html
Copyright © 2011-2022 走看看