异或链表(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. linux查看系统类型和版本

    首先大致普及下linux系统的版本内容. 1.内核版本和发行版本区别 我的理解,内核版本就是指linux中最基层的代码,版本号如 Linux version 3.10.0-327.22.2.el7.x ...

  2. 使用SeasLog打造PHP项目中的高性能日志组件(一)

    云智慧(北京)科技有限公司 高驰涛 什么是SeasLog SeasLog是一个C语言编写的PHP扩展,提供一组规范标准的功能函数,在PHP项目中方便.规范.高效地写日志,以及快速地读取和查询日志. 为 ...

  3. webservice 接口通过 HTTP 获取数据

    using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Ne ...

  4. Data import/export of Netezza using external table

    Introduction External table is a special table in Netezza system, which could be  used to import/exp ...

  5. otter双主同步安装与配置

    otter是阿里的开源数据同步项目,资源地址就不用说了哈,网上找,阿里云论坛关于单方向同步的配置已经很清楚了,理论上说,双主同步也不复杂,但是毕竟 是数据库,比较重要,配置双主的时候,总觉得心里没底, ...

  6. 安卓代码覆盖率:android studio+ gradle+jacoco

    在工程的oncreate()方法添加如下代码,目的是创建ec文件. String DEFAULT_COVERAGE_FILE_PATH = "/mnt/sdcard/coverage.ec& ...

  7. 应用程序缓存--manifest

    应用程序缓存(Application Cache)为应用带来三个优势: 离线浏览 - 用户可在应用离线时使用它们 速度 - 已缓存资源加载得更快 减少服务器负载 - 浏览器将只从服务器下载更新过或更改 ...

  8. 【私人定制jackson】定制jackson的自定义序列化(null值的处理)

    最近用springMVC做服务端的http+json的接口,出现一个不是特别容易解决的问题: 在对List类型的值进行处理时,有一部分服务是有做一些逻辑判断的,在逻辑判断不通过的时候会返回一个null ...

  9. 引用模板中的类型时,切记要加上typename声明!!

    如题,发现实际操作中太容易忘记了,导致一些莫名其妙的编译错误,故在此记录!

  10. sql删除前导和后缀

    1.patindex用法 patindex('%pattern%', expression) pattern--> 正则表达式,需要匹配的前导内容,可以进通配: expression--> ...