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;
    }
  • 相关阅读:
    关于hibernate的缓存使用(转)
    Webservice 实践
    三大电商注册登录表单分析
    网上好文搜集
    git简介
    Python程序中的进程操作--—--开启多进程
    进程的创建和结束
    同步异步阻塞和非阻塞
    进程的并行和并发
    进程调度
  • 原文地址:https://www.cnblogs.com/tiny656/p/4108976.html
Copyright © 2011-2022 走看看