【数据结构(ywm版)】异或指针双向链表
在《数据结构题集》中看到这种链表,实际上就是把一般的双向链表的next和prior两个指针通过异或运算合并为一个指针域来存储,每个结点确实可以减少一个指针的空间,但会带来取指针值时运算的开销。
实现的时候,先搞清双向链表,把握异或指针域的原理公式,然后从双向链表出发进行转换即可。
typedef struct XorNode{ //结点的定义
ElemType data;
struct XorNode* LRPtr;
}XorNode, *XorPointer;
typedef struct{//无头结点的异或指针双向链表
XorPointer Left, Right; //只保存指向首、末结点的指针
}XorList;
每个结点的指针域存的是它的前驱和后继的异或值,即 LRPtr = prior ^ next,指针异或运算本质上就是整型的内存地址的按位异或。
//指针异或函数,注意指针变量不支持^运算,需要强转为整型(内存地址,长度与机器有关,C将之封装为size_t型)
XorPointer XorP(XorPointer p, XorPointer q){
size_t x = (size_t)p;
size_t y = (size_t)q;
return (XorPointer)(x^y);
}
这相当于把前驱和后继的指针编码到一个指针域中了,那么如何解码呢,只凭LRPtr本身是不可以的,必须再已知prior或next才行,这得益于异或运算特有的“对称”性质。
异或运算满足结合律,0为幺元,每个元素和自身互为逆元;所以设a, b为两个内存地址,则有
a^(a^b) = (a^a)^b = b;
(a^b)^b = a^(b^b) = a;
有了这两条,则可推出取得前驱或后继的式子,即
prior = LRPtr ^ next;
next = prior ^ LRPtr;
根据这两个关系,把双向链表的next和prior的运算用LRPtr替换即可。注意由于是循环链表,只有一个元素时,其前驱和后继都为自身。
注意我实现的是无头结点的循环链表,而链表的表长又不是显式维护的,所以要以回到起点作为循环退出条件之一,并设一个记录步数的变量k来避免 i 值超过表长而导致的“兜圈子”;在边界操作时注意修改首末元素指针。
Status CreateList(XorList& L, int n){
//头插法建表,无头结点,入口条件:n>=1
n--;
XorPointer p;
p = (XorPointer)malloc(sizeof(XorNode));
L.Left = L.Right = p;
p->data = n;
p->LRPtr = XorP(p, p);
while(n--){
p = (XorPointer)malloc(sizeof(XorNode));
p->data = n;
p->LRPtr = XorP(L.Right, L.Left);
L.Left->LRPtr = XorP(p, XorP(L.Right, L.Left->LRPtr));
L.Right->LRPtr = XorP(XorP(L.Right->LRPtr,L.Left),p);
L.Left = p;
}
}
Status Insert(XorList& L, int i, ElemType e){
//在第i个位置前插入结点e(i的合法值为1~表长+1)
//由于无头结点,故判断表长是否够i,要通过计步变量k
XorPointer p = L.Left, q = L.Right;
int k = ;
while(p!=L.Right && k<i){ //p指向i, q指向i-1;保证至多扫描一遍后退出
XorPointer t = p;
p = XorP(q, p->LRPtr);
q = t;
k++;
}
if(k+<i) return ERROR; //表长不够i-1
if(k+==i){p = L.Left; q = L.Right;} //插到表长+1的位置,即最后一个元素之后
XorPointer s = (XorPointer)malloc(sizeof(XorNode));
s->data = e;
s->LRPtr = XorP(q, p);
q->LRPtr = XorP(XorP(q->LRPtr, p), s);
p->LRPtr = XorP(s, XorP(q, p->LRPtr));
if(i==) L.Left = s;
if(i==k+) L.Right = s;
return OK;
}
Status Delete(XorList& L, int i, ElemType& e){
//删除第i个位置的元素,用e返回其值(i的合法值为1~表长)
XorPointer p = L.Left, q = L.Right;
int k = ;
while(p!=L.Right && k<i){ //p指向i, q指向i-1
XorPointer t = p;
p = XorP(q, p->LRPtr);
q = t;
k++;
}
if(k<i) return ERROR; //表长不够i
if(p==L.Right) L.Right = q; //删除最后一个结点
e = p->data;
XorPointer m = XorP(q, p->LRPtr); //m暂存p的后继
q->LRPtr = XorP(XorP(q->LRPtr, p), m);
m->LRPtr = XorP(q, XorP(p, m->LRPtr));
free(p);
if(i==) L.Left = m; //删除第一个结点
return OK;
}
Status Traverse(XorList& L, void (*visit)(XorNode)){
XorPointer p = L.Left, q = L.Right;
while(p != L.Right){
visit(*p);
XorPointer t = p;
p = XorP(q,p->LRPtr);
q = t;
}
visit(*p);
return OK;
}
void print(XorNode xn){
printf("[%d]",xn.data);
}
int main()
{
XorList l;
CreateList(l,);
ElemType e;
if(Delete(l,,e))
Traverse(l,print);
return ;
}
【数据结构(ywm版)】异或指针双向链表的更多相关文章
- SDUT OJ 数据结构实验之链表九:双向链表
数据结构实验之链表九:双向链表 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Discuss Problem Descrip ...
- SDUT-2054_数据结构实验之链表九:双向链表
数据结构实验之链表九:双向链表 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 学会了单向链表,我们又多了一种解决问题的 ...
- 大话数据结构(八)Java程序——双向链表的实现
线性链表--双向链表 双向链表定义: 双向链表(double linked list): 是在单表单的每个结点中,再设置一个指向前驱结点的指针域.因此,在双向链表中的结点都有两个指针域,一个指向前驱, ...
- C和C指针小记(十八)-使用结构和指针-双向链表
1.双链表 1.1 双向链表的声明 在一个双链表中,每个节点都包含两个指针--指向前一个节点的指针和指向后一个节点的指针. 声明 typedef struct NODE { struct NODE * ...
- 数据结构复习之C语言指针与结构体
数据结构指针复习: #include <stdio.h> void main() { ] = {, , , , }; // a[3] == *(3+a) printf(+a)); // a ...
- 数据结构笔记1(c++)_指针
一.数据结构概述 1.定义: 我们如何把现实中大量而复杂的问题,以特定的数据类型和特定的存储结构保存到主存储器(内存)中,以及在此基础上为实现某个功能(比如查找某个元素,删除某个元素,对所有元素进行排 ...
- 数据结构C++版-队列
一.概念 分类: 二.补充说明 1.<面向对象的队列设计>课程问答: 首先要明确数据结构和数据存储结构的概念. 数据结构是指数据对象之间的逻辑关系,例如二叉树,队列,栈等,而数据存储结构是 ...
- cocos2dx解析lua table数据结构 简易版.
之前一直用xml填配置, cocos2dx自带了xml解析接口, 非常方便. 但是, 接口好用也改变不了xml的结构字符太多, 书写麻烦, 乱七八糟的事实. 很早就想换lua, 无奈引擎没有现成接口, ...
- 数据结构Java版之交换算法(一)
交换的本质是拷贝,其中拷贝包括两种方式.值拷贝和指针拷贝,在java中没有指针,为此,我们可以理解为地址拷贝,在我看来,指针就是地址. 1.传值方式示例: 由上述示例可得,传值,不能起到交换的作用,原 ...
随机推荐
- 学习 ExtJS 4 面板与布局
原文 http://www.cnblogs.com/codealone/archive/2013/06/04/3091325.html 面板Panel Ext.panel.Panel拓展自Ext.co ...
- 如何提升app开发效率
无论在什么行业,用户永远都是不可替代的“上帝”,一切的服务,开发都得按照用户的意愿来进行.然而在app开发领域中,专业的技术操作却并不像逛街淘货一样清晰可见,更多的需要app开发人员一行行代码敲出来, ...
- LintCode-A + B 用位操作模拟加法
class Solution { public: /* * @param a: The first integer * @param b: The second integer * @return: ...
- poj 1020 Anniversary Cake(切正方形蛋糕+搜索)
...
- python连续爬取多个网页的图片分别保存到不同的文件夹
python连续爬取多个网页的图片分别保存到不同的文件夹 作者:vpoet mail:vpoet_sir@163.com #coding:utf-8 import urllib import ur ...
- 带你走近AngularJS - 创建自己定义指令
带你走近AngularJS系列: 带你走近AngularJS - 基本功能介绍 带你走近AngularJS - 体验指令实例 带你走近AngularJS - 创建自己定义指令 ------------ ...
- Codevs1992题解
题目大意 求有向图中经过某一点k的最大环(数据规模不支持floyd). 题解 以k为起点在正向图中spfa求单源最短路.再在反向图中spfa求单源最短路. 枚举除k外的每个点i.假设有一个同一时候包括 ...
- Oracle SQL函数之日期函数
sysdate [功能]:返回当前日期. [参数]:没有参数,没有括号 [返回]:日期 SQL> SELECT SYSDATE FROM DUAL; SYSDATE ----------- // ...
- js 去掉空格
写成类的方法格式如下:(str.trim();)<script language="javascript"> String.prototype.trim=functio ...
- C++中如何split字符串(转)
#include <iostream> #include <sstream> #include <string> using namespace std; int ...