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

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

  1. XOR linked list--- 异或链表

    异或链表的结构 这是一个数据结构.利用计算机的的位异或操作(⊕),来降低双向链表的存储需求. ... A B C D E ... –> next –> next –> next –& ...

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

    注:在吴恩达老师讲的[机器学习]课程中,最开始介绍神经网络的应用时就介绍了含有一个隐藏层的神经网络可以解决异或问题,而这是单层神经网络(也叫感知机)做不到了,当时就觉得非常神奇,之后就一直打算自己实现 ...

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

    如何使用异或(XOR)运算找到数组中缺失的数? 今天给大家分享一篇关于使用XOR(异或)运算找到数组中缺失的数的问题. 在一次Javascript面试中,有这么一个问题: 假设有一个由0到99(包含9 ...

  4. LeetCode 234:回文链表 Palindrome Linked List

    ​ 请判断一个链表是否为回文链表. Given a singly linked list, determine if it is a palindrome. 示例 1: 输入: 1->2 输出: ...

  5. 链表(Linked List)

    链表(Linked List) 一.介绍 链表是有序的列表,它在内存中存储方式(物理存储)如下: 小结: (1)链表是以节点的方式来存储,是链式存储. (2)每个节点包含 data 域:存储数据:ne ...

  6. 【数据结构与算法】——链表(Linked List)

    链表(Linked List)介绍 链表是有序的列表,但是它在内存中是存储如下: 链表是以节点的方式来存储的,是链式存储. 每个节点包含data域,next域:指向下一个节点. 如图:链表的各个节点不 ...

  7. 关于异或(Xor)的一点笔记

    因为博弈论里,尤其实在求sg函数时,经常会用到异或运算,所以我就把网上搜到的一些相关知识和自己的一些理解记下来. 如果出现差错,还请指出,谢谢! 异或:可以简称Xor,可以用数学符号⊕表示,计算机就一 ...

  8. LeetCode之“链表”:Linked List Cycle && Linked List Cycle II

    1.Linked List Cycle 题目链接 题目要求: Given a linked list, determine if it has a cycle in it. Follow up: Ca ...

  9. [Swift]LeetCode142. 环形链表 II | Linked List Cycle II

    Given a linked list, return the node where the cycle begins. If there is no cycle, return null. Note ...

随机推荐

  1. google map 计算地图面积方法

    花了几个小时把js的google计算地图面积的算法改成了c# 的. class Program { static void Main(string[] args) { // a = new qq.ma ...

  2. js获取鼠标当前的位置

    有时候,我们需要得到窗口拖动或者鼠标移动的距离,此时可以通过计算鼠标前后在页面中的位置来得到想要的结果,下面介绍几个事件属性: 1.客户区坐标位置 鼠标事件都是在浏览器视口中的特定位置上发生的.这个位 ...

  3. Noip2016提高组 组合数问题problem

    Day2 T1 题目大意 告诉你组合数公式,其中n!=1*2*3*4*5*...*n:意思是从n个物体取出m个物体的方案数 现给定n.m.k,问在所有i(1<=i<=n),所有j(1< ...

  4. git 调用 Beyond Compare

    转载自  http://www.jackness.org/2015/03/31/git-%E8%B0%83%E7%94%A8-%E7%AC%AC%E4%B8%89%E6%96%B9%E5%AF%B9% ...

  5. nginx php-fpm安装配置

    nginx本身不能处理PHP,它只是个web服务器,当接收到请求后,如果是php请求,则发给php解释器处理,并把结果返回给客户端. nginx一般是把请求发fastcgi管理进程处理,fascgi管 ...

  6. Slight difference between C++ and C

    In C++, results of assignment operation, prefix increment and prefix decrement are all lvalues, the ...

  7. [LeetCode][Java]Triangle@LeetCode

    Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent n ...

  8. rdlc报表DEMO

    rdlc报表demo  .net 4.0  vs2013 文本框,图像控件,checkbox样式的打印 下载链接

  9. XAF学习笔记之-多表头设计

    空闲之余,看了下全英文的DEV 的XAF帮助文档,一半的英文我认识他,一半的英文他认识我,反正拆开成26个字母我全认识 不那么啰嗦了,先看效果 如何做:分以下几步 第一步:打开这个文件,这个文件就是X ...

  10. Keras Installation

    #Install numpy and scipy sudo apt-get install gfortran libopenblas-dev liblapack-dev libatlas-base-d ...