异或链表(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;
}
异或链表(XOR linked list)的更多相关文章
- XOR linked list--- 异或链表
异或链表的结构 这是一个数据结构.利用计算机的的位异或操作(⊕),来降低双向链表的存储需求. ... A B C D E ... –> next –> next –> next –& ...
- 【机器学习】神经网络实现异或(XOR)
注:在吴恩达老师讲的[机器学习]课程中,最开始介绍神经网络的应用时就介绍了含有一个隐藏层的神经网络可以解决异或问题,而这是单层神经网络(也叫感知机)做不到了,当时就觉得非常神奇,之后就一直打算自己实现 ...
- 【ShareCode】不错的技术文章 -- 如何使用异或(XOR)运算找到数组中缺失的数?
如何使用异或(XOR)运算找到数组中缺失的数? 今天给大家分享一篇关于使用XOR(异或)运算找到数组中缺失的数的问题. 在一次Javascript面试中,有这么一个问题: 假设有一个由0到99(包含9 ...
- LeetCode 234:回文链表 Palindrome Linked List
请判断一个链表是否为回文链表. Given a singly linked list, determine if it is a palindrome. 示例 1: 输入: 1->2 输出: ...
- 链表(Linked List)
链表(Linked List) 一.介绍 链表是有序的列表,它在内存中存储方式(物理存储)如下: 小结: (1)链表是以节点的方式来存储,是链式存储. (2)每个节点包含 data 域:存储数据:ne ...
- 【数据结构与算法】——链表(Linked List)
链表(Linked List)介绍 链表是有序的列表,但是它在内存中是存储如下: 链表是以节点的方式来存储的,是链式存储. 每个节点包含data域,next域:指向下一个节点. 如图:链表的各个节点不 ...
- 关于异或(Xor)的一点笔记
因为博弈论里,尤其实在求sg函数时,经常会用到异或运算,所以我就把网上搜到的一些相关知识和自己的一些理解记下来. 如果出现差错,还请指出,谢谢! 异或:可以简称Xor,可以用数学符号⊕表示,计算机就一 ...
- 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 ...
- [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 ...
随机推荐
- 初学c# -- 学习笔记(五) winfrom自定义滚动条
找了些例子,要么庞大.要么搞个安装组件什么的,我要求能用就行了.实在找例子修改麻烦,就做了一个.其实实现挺简单,就是panel或图片什么的跟着鼠标走就行了. 这里panel自己可以加背景图或直接搞个图 ...
- mongodb sharding 简单部署记录
创建目录 mkdir {mongos,config,shard1,shard2} mkdir -p mongos/{data,log} mkdir -p config/{data,log} mkdir ...
- Android Studio开发基础之自定义View组件
一般情况下,不直接使用View和ViewGroup类,而是使用使用其子类.例如要显示一张图片可以用View类的子类ImageView,开发自定义View组件可分为两个主要步骤: 一.创建一个继承自an ...
- 关于js原型继承
js的每个类都有一个prototype对象 访问对象的属性时,会先访问到对象自身是否有定义这个属性 如果没有定义,就会去访问对象所属类型的prototype对象是否有此属性 原型继承就是把类型的pro ...
- HFSS设计导入AD中
具体过程有些繁琐,录制了一个视频放在百度网盘了.亲测有效. 网盘地址:http://pan.baidu.com/s/1gfIBhC3 密码:ayoa
- Git学习(三)——暂存区、远程仓库、增删改管理
一.工作区和暂存区 工作区(Working Directory) 就是在你的电脑里能看到的目录 版本库(Repository) 工作区中的一个隐藏目录.git,这个不算工作区,而是Git版本库.Git ...
- Android新建数据库和建表demo
public class DBHelper extends SQLiteOpenHelper{ public final static String DATABASENAME ="diary ...
- 初涉定制linux系统之——自动化安装Centos系统镜像制作
最近碰到个需求:要在内网环境安装centos6.5系统并搭建服务,但由于自动部署脚本里安装依赖包使用的是yum安装,而服务器无法连接外网,实施人员也不会本地yum源搭建O__O "….. 本 ...
- Trie / Radix Tree / Suffix Tree
Trie (字典树) "A", "to", "tea", "ted", "ten", "i ...
- 如何在在WinFrom的DataGridView中做到数据持续动态加载而不卡死
1.在这个过程我用过好几种办法 (1)使用委托的办法,这个方法可以做到持续加载,但是效果不理想会卡死 (2)开启线程的方法,会造成卡死 (3)使用另一个窗体的线程做持续加载(子窗体),让子窗体作为一个 ...

