【数据结构(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.传值方式示例: 由上述示例可得,传值,不能起到交换的作用,原 ...
随机推荐
- kibana 日志查看界面
- Linux系统编程(11)——进程间通信之有名管道
管道应用的一个重大限制是它没有名字,因此,只能用于具有亲缘关系的进程间通信,在有名管道(named pipe或FIFO)提出后,该限制得到了克服.FIFO不同于管道之处在于它提供一个路径名与之关联,以 ...
- Grunt制作个人博客简集
原文:http://www.gbtags.com/gb/share/4916.htm GitHub地址:http://yansm.github.io/fromone/
- postgresql基本语句
preface,熟悉pgsql sql Language article disorder; 1,pgsql数据库控制台Cli(command line interface) help mannual ...
- PHP 表单验证 - 必填字段
-------------------------------------------------------------------------- 本节展示如何制作必填输入字段,并创建需要时所用的错 ...
- Pasha and String(思维,技巧)
Pasha and String Time Limit:2000MS Memory Limit:262144KB 64bit IO Format:%I64d & %I64u S ...
- Yeslab现任明教教主数据中心第二门课程UCS 视频教程下载
Yeslab现任明教教主数据中心第二门课程UCS 视频教程下载 视频教程目录 Yeslab现任明教教主数据中心第二门课程UCS.1.介绍UCS.rar Yeslab现任明教教主数据中心第二门课程UCS ...
- cloudstack4.4新增功能前瞻
cloudstack4.4.0新功能前瞻 转载请注明地址:http://blog.csdn.net/zt689/article/details/37698989 1. cloudstack4.4. ...
- stagefright框架(七)-Audio和Video的同步
讲完了audio和video的处理流程,接下来要看的是audio和video同步化(synchronization)的问题.OpenCORE的做法是设置一个主clock,而audio和video就分别 ...
- 第002篇 深入体验C#项目开发(一)
网上摘来的简介: <深入体验C#项目开发>通过10个综合实例的实现过程,详细讲解了C#在实践项目中的综合运用过程.这些项目从作者的学生时代写起,到项目经理结束,一直贯穿于作者 ...