异或链表(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. visual foxpro命令

    根据条件查看已打开dbf表单的记录----LIST ALL FIELDS FOR =''   最后按一下enter键

  2. mysql 常用基础

    登录命令 -h远程IP地址 -u用户名 -p密码 -P端口 mysql -h127.0.0.1 -uroot -p21313 -P3306 新建用户 insert into mysql.user(Ho ...

  3. oracle异常写法

    EXCEPTION WHEN OTHERS THEN V_ALARM_MSG := SQLERRM; --错误日志表 V_SQLTEXT := 'CALL DD_PAK.ERRLOG(:V1,:V2, ...

  4. JSP(include指令与<jsp:include>动作的区别)

    <%@ page language= "java" contentType="text/html;charset=UTF-8" %><html ...

  5. Android版本4.0~7.0

    Android 4.0 Ice Cream Sandwich(冰激凌三明治):2011年10月19日发布 版本主要更新如下:全新的UI:全新的Chrome Lite浏览器:截图功能:更强大的图片编辑功 ...

  6. h5弹框去掉ip地址

    <script> window.alert = function(name){ var iframe = document.createElement("IFRAME" ...

  7. 一个div,包含三个小的div,平均分布的样式

    从11月份开始,自学前端开发,写静态页面中,经常用到一个大的div下包含三个小的div,平均分布div大小样式,写过多次,也多次忘记,每次都要现找资料,不想之后,在这么麻烦,索性今天自己记录一下,方便 ...

  8. 序列化--dict与(file)文件读写

    在程序运行的过程中,所有的变量都是在内存中,比如,定义一个dict: d = dict(name='Bob', age=20, score=88) 可以随时修改变量,比如把name改成'Bill',但 ...

  9. c语言折半查找

    折半查找又称为二分查找,它的前提是线性表中的记录必须是有序的(通常从小到大有序),线性表必须采用顺序存储. 折半查找的基本思想是 : 在有序表中,取中间记录作为比较对象,若给定值与中间记录的关键字相等 ...

  10. mysql常见命令

    1.进入mysql:mysql -u root -p 2.允许远程访问: mysql -u root –p mysql>use mysql; mysql>update user set h ...