在《数据结构题集》中看到这种链表,实际上就是把一般的双向链表的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版)】异或指针双向链表的更多相关文章

  1. SDUT OJ 数据结构实验之链表九:双向链表

    数据结构实验之链表九:双向链表 Time Limit: 1000 ms Memory Limit: 65536 KiB Submit Statistic Discuss Problem Descrip ...

  2. SDUT-2054_数据结构实验之链表九:双向链表

    数据结构实验之链表九:双向链表 Time Limit: 1000 ms Memory Limit: 65536 KiB Problem Description 学会了单向链表,我们又多了一种解决问题的 ...

  3. 大话数据结构(八)Java程序——双向链表的实现

    线性链表--双向链表 双向链表定义: 双向链表(double linked list): 是在单表单的每个结点中,再设置一个指向前驱结点的指针域.因此,在双向链表中的结点都有两个指针域,一个指向前驱, ...

  4. C和C指针小记(十八)-使用结构和指针-双向链表

    1.双链表 1.1 双向链表的声明 在一个双链表中,每个节点都包含两个指针--指向前一个节点的指针和指向后一个节点的指针. 声明 typedef struct NODE { struct NODE * ...

  5. 数据结构复习之C语言指针与结构体

    数据结构指针复习: #include <stdio.h> void main() { ] = {, , , , }; // a[3] == *(3+a) printf(+a)); // a ...

  6. 数据结构笔记1(c++)_指针

    一.数据结构概述 1.定义: 我们如何把现实中大量而复杂的问题,以特定的数据类型和特定的存储结构保存到主存储器(内存)中,以及在此基础上为实现某个功能(比如查找某个元素,删除某个元素,对所有元素进行排 ...

  7. 数据结构C++版-队列

    一.概念 分类: 二.补充说明 1.<面向对象的队列设计>课程问答: 首先要明确数据结构和数据存储结构的概念. 数据结构是指数据对象之间的逻辑关系,例如二叉树,队列,栈等,而数据存储结构是 ...

  8. cocos2dx解析lua table数据结构 简易版.

    之前一直用xml填配置, cocos2dx自带了xml解析接口, 非常方便. 但是, 接口好用也改变不了xml的结构字符太多, 书写麻烦, 乱七八糟的事实. 很早就想换lua, 无奈引擎没有现成接口, ...

  9. 数据结构Java版之交换算法(一)

    交换的本质是拷贝,其中拷贝包括两种方式.值拷贝和指针拷贝,在java中没有指针,为此,我们可以理解为地址拷贝,在我看来,指针就是地址. 1.传值方式示例: 由上述示例可得,传值,不能起到交换的作用,原 ...

随机推荐

  1. tar解压错误

    # tar -zxvf aaa.tar.gz    tar: This does not look like a tar archive   tar: Skipping to next header ...

  2. codecomb 2100【警察叔叔就是这个人!】

    题目背景 十个地方十人十色 全部都是猥琐大叔 这里也是那里也是 行踪可疑 现如今hentai横行,警察叔叔们不得不采取特♂殊手段惩戒这些家伙 题目描述 魅力之都是一个有N个路口,M条双向道路连接的城市 ...

  3. ubuntu下hadoop完全分布式部署

    三台机器分别命名为: hadoop-master ip:192.168.0.25 hadoop-slave1 ip:192.168.0.26 hadoop-slave2 ip:192.168.0.27 ...

  4. 国际C语言混乱代码大赛代码赏析(一)【转】

    本文转载自:http://blog.csdn.net/ce123_zhouwei/article/details/9073869 国际C语言混乱代码大赛代码赏析(一) 近段时间在看<C专家编程& ...

  5. poj 3411 Paid Roads(dfs)

    Description A network of m roads connects N cities (numbered to N). There may be more than one road ...

  6. Unity编辑器扩展Texture显示选择框

    学习NGUI插件的时候,突然间有一个问题为什么它这些属性可以通过弹出窗口来选中呢? 而我自己写的组件只能使用手动拖放的方式=.=. Unity开发了组件Inspector视图扩展API,如果我们要写插 ...

  7. NSNotificationCenter 传对象

    [[NSNotificationCenter defaultCenter] postNotificationName:@"postCity" object:pro]; [[NSNo ...

  8. Android开发之Intent.Action

    1 Intent.ACTION_MAIN String: android.intent.action.MAIN 标识Activity为一个程序的開始.比較经常使用. Input:nothing Out ...

  9. ubuntu下安装xlrd模块,Mysqldb模块

    Python中安装xlrd模块 1.从 https://pypi.python.org/pypi/xlrd  下载压缩包 2.解压所下载的压缩包 3.CD到解压文件夹,运行 sudo python s ...

  10. poj1184 聪明的打字员(BFS剪枝)

    http://poj.org/problem?id=1184 用字符串s存下数字,并把光标位置做一个字符加到s末尾,用map做标记状态是否出现过,然后bfs即可. 不剪枝是过不了的,考虑的两种交换操作 ...