1.意义
其实双向链表每个节点在空间复杂度上还有优化的地方 比如在原本的双向链表的每一个节点中 都储存了三个内存 一个用于存储节点值 一个用于指向前置节点 一个用于指向后置节点 他的目的就在于通过任意节点可以访问到其前置节点以及后置节点 其实我们每个节点储存两个内存也可以达到这个目的 这就是我们今天所要讲述的异或链表
2.异或链表
异或链表是在双向链表的基础上进行了空间复杂度的优化 并且能够达到相同的功能
在这个链表中 每个节点都储存了两个内存 一个用于储存节点值 一个用于储存前置节点以及后置节点的地址值的异或结果
如果你想要访问当前节点的前置节点的话 那么你就可以通过当前节点的link(link就是用来储存前置节点地址值和后直节点地址值的异或结果的)异或后置节点的地址值即可获取到前置节点的地址值 然后就可以访问到当前节点的前置节点了
同理你想要访问当前节点的后置节点也是一样道理
3.代码实现
由于c或者c++这类的编程语言可以直接访问地址值 而Java等其他语言不能够直接访问地址值 所以我们不便使用Java去实现异或链表 所以通过c++来实现 这是异或链表的局限性
#include <iostream>
#include <vector>
#include <cstdint>
using namespace std;
// 定义一个结构体 视为节点类
struct Node {
// 节点值
int value;
// 前置节点的地址值和后置节点地址值的异或结果
Node* link;
};
// 定义一个函数 用于返回参数的异或结果
Node* XOR(Node* x, Node* y) {
return (Node*)((uintptr_t)(x) ^ (uintptr_t)(y));
}
// 定义一个函数 用于遍历链表 并且同时打印节点值
void traverse(Node* head) {
// 首先定义一个节点指针 用于保存前置节点的地址值
Node* pre = nullptr;
// 定义一个节点指针 用于指向当前节点
struct Node* cur = head;
// 定义一个节点指针 用于指向后置节点
struct Node* next;
// 如果当前节点不为空的话 那么直接打印当前节点的节点值
while (cur != nullptr) {
cout << cur->value << "->";
next = XOR(pre, cur->link);
pre = cur;
cur = next;
}
// 等到循环结束以后 最后节点为空
cout << "nullptr" << endl;
}
// 定义一个函数 用于往头部添加节点
void push(Node** head, int value) {
// 首先创建一个结构体变量 设置该变量的value为指定参数
Node* newNode = new Node();
newNode->value = value;
newNode->link = XOR(nullptr, *head);
// 如果原链表中存在节点的话 那么需要更新头结点信息
if (*head) {
(*head)->link = XOR(newNode, XOR((*head)->link, nullptr));
}
// 更新头结点
*head = newNode;
}
int main() {
// 首先创建一个数组 用于存放节点值数据
vector<int> result = { 1, 2, 3, 4, 5 };
Node* head = nullptr;
for (int i = result.size() - 1; i >= 0; --i) {
push(&head, result[i]);
}
traverse(head);
return 0;
}