Tiny656

我不会轻易流泪,直到我的梦想成为现实,我再将所有的辛苦和泪水抛洒。

异或链表(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;
}

posted on 2014-11-19 19:16  Tiny656  阅读(2646)  评论(0编辑  收藏  举报

导航