异或链表(XOR linked list)

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

普通的双向链表

class Node {
public:
    int data;
    Node *prev;
    Node *next;
};

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

对于异或链表来说,只是用一个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异或指针,异或指针记录前后两个指针的地址值的异或值

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;
}
时间: 2024-10-25 21:17:23

异或链表(XOR linked list)的相关文章

异或链表(XOR Linked List)

一.常见的链表 1.单链表(Singly Linked List) 构成:每个节点包含数据(data)和后继节点的地址(next) 2.双向链表 构成:每个节点包含数据(data).前驱的地址(prev).后继的地址(next) 优势:删除或添加元素不需要移动数据,可以双向遍历 3.异或链表(XOR Linked List) 构成:每个节点包含数据(data).前驱地址和后继地址的异或 是一种实现双向链表的方法,它 增加了代码复杂度,降低了空间复杂度,随着内存设备不断发展,空间要求降低. 小例子

待字闺中之快排(QuickSort)单向链表(Singly Linked List)

题目来源,待字闺中,原创@陈利人 ,欢迎大家继续关注微信公众账号"待字闺中" 分析:思路和数据的快速排序一样,都需要找到一个pivot元素.或者节点.然后将数组或者单向链表划分为两个部分,然后递归分别快排. 针对数组进行快排的时候,交换交换不同位置的数值,在分而治之完成之后,数据就是排序好的.那么单向链表是什么样的情况呢?除了交换节点值之外,是否有其他更好的方法呢?可以修改指针,不进行数值交换.这可以获取更高的效率. 在修改指针的过程中,会产生新的头指针以及尾指针,要记录下来.在par

【机器学习】神经网络实现异或(XOR)

注:在吴恩达老师讲的[机器学习]课程中,最开始介绍神经网络的应用时就介绍了含有一个隐藏层的神经网络可以解决异或问题,而这是单层神经网络(也叫感知机)做不到了,当时就觉得非常神奇,之后就一直打算自己实现一下,一直到一周前才开始动手实现.自己参考[机器学习]课程中数字识别的作业题写了代码,对于作业题中给的数字图片可以达到95%左右的识别准确度.但是改成训练异或的网络时,怎么也无法得到正确的结果.后来查了一些资料才发现是因为自己有一个参数设置的有问题,而且学习率过小,迭代的次数也不够.总之,异或逻辑的

【ShareCode】不错的技术文章 -- 如何使用异或(XOR)运算找到数组中缺失的数?

如何使用异或(XOR)运算找到数组中缺失的数? 今天给大家分享一篇关于使用XOR(异或)运算找到数组中缺失的数的问题. 在一次Javascript面试中,有这么一个问题: 假设有一个由0到99(包含99)的整数组成的长度为100的数组.从数组中随机移除一个元素,得到了一个长度为99的数组,那么请问如何找到所取出的数字是几?(假设数组未排序). 大多数面试者都是按照如下方法解答的: 首先对数组进行排序,然后遍历一遍数组,检查数组中相邻两项的的差,如果差大于1,则找到缺失的数字. 这是一种有效的算法

链表(Linked List): 单链表

链表(Linked List)介绍 链表是有序的列表,但是它在内存中是存储如下: 小结: 链表是以节点的方式来存储,是链式存储. 每个节点包含 data域 , next域 : 指向下一个节点. 如图:发现链表的各个节点不一定是连续存储. 链表分带头节点的链表 和 没有带头节点的链表,根据实际的需求来确定. 单链表介绍 单链表(带头节点)逻辑结构示意图如下: 单链表的应用实例 使用带head头的单向链表实现—水浒英雄排行榜管理完成对英雄人物的增删改查操作. 1)第一种方法在添加英雄时,直接添加到链

LeetCode 206 链表 Reverse Linked List

LeetCode 206 链表 Reverse Linked List Reverse a singly linked list. Example: Input: 1->2->3->4->5->NULL Output: 5->4->3->2->1->NULL Follow up: A linked list can be reversed either iteratively or recursively. Could you implement

234. 回文链表 Palindrome Linked List

Given a singly linked list, determine if it is a palindrome. Follow up:Could you do it in O(n) time and O(1) space? 判断一个链表是否为回文串 思路:1.找到中间点,2.反转后半部分链表,3.判断前半部分与后半部分是否相同 /** * Definition for singly-linked list. * public class ListNode { * public int v

LeetCode之“链表”:Linked List Cycle &amp;&amp; Linked List Cycle II

1. Linked List Cycle 题目链接 题目要求: Given a linked list, determine if it has a cycle in it. Follow up: Can you solve it without using extra space? 刚看到这道题,很容易写出下边的程序: 1 bool hasCycle(ListNode *head) { 2 ListNode *a = head, *b = head; 3 while(a) 4 { 5 b =

对文件异或(xor)解密的方法

这里对异或做下简单的解释,异或是一种2进制的运算,这里举个简单的例子 1^1=0 1^0=1 两者相同则为0,不同则为1 a的二进制是01100001 b的二进制是01100010 逐位比较得到00000011,然后转为十进制就是3,则a^b=3 下面以实验吧的一道题目为例 下载压缩包得到两个txt文件,其中一个是密文,另外一个是明文,根据题目提示可以想到是文件异或 密文和明文的内容如下 所以我们对它们进行异或 python代码如下 # -*- coding: cp936 -*-a=open('