在《数据结构题集》中看到这种链表,实际上就是把一般的双向链表的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. Linux下GDB调试C/C++

    首先先编译程序并生成调试符号: gcc -g -c main.cpp gcc -o exefile main.o 以上的exefile为可执行程序的文件名 然后: gdb exefile 可以开始gd ...

  2. Clone Graph 解答

    Question Clone an undirected graph. Each node in the graph contains a label and a list of its neighb ...

  3. Unique Binary Search Trees II 解答

    Question Given n, generate all structurally unique BST's (binary search trees) that store values 1.. ...

  4. Impala 1、Impala理论

    1.Impala简介 • Cloudera公司推出,提供对HDFS.Hbase数据的高性能.低延迟的交互式SQL查询功能. • 基于Hive使用内存计算,兼顾数据仓库.具有实时.批处理.多并发等优点 ...

  5. vue.js的devtools安装

    安装 1.github下载地址:https://github.com/vuejs/vue-devtools 2.下载好后进入vue-devtools-master工程  执行npm install - ...

  6. MVC实用架构设计:总体设计

    http://developer.51cto.com/art/201309/410166.htm

  7. Zjnu Stadium(hdu3047带权并查集)

    题意:一个300列的无限行的循环场地,a b d代表a,b顺时针相距d的距离,现在给你一些距离,判断是否有冲突,如果有冲突计算冲突的次数 思路:带权并查集 a,b的距离等于b到根节点的距离 - a到根 ...

  8. stagefright框架(一)Video Playback的流程

    在Android上,預設的多媒體框架(multimedia framework)是OpenCORE. OpenCORE的優點是兼顧了跨平台的移植性,而且已經過多方驗證,所以相對來說較為穩定:但是其缺點 ...

  9. React-Native ListView加载图片淡入淡出效果的组件

    今天练习项目中需要给listview在加载图片时增加一个淡入淡出的效果,因此干脆就自己封装了一个组件: 'use strict' import React from 'react-native' va ...

  10. Failed to create the Java Virtual Machine (Myeclipse或者eclipse启动报错)

    把某几个值改为原来的0.5倍就ok了(我就这么解决的)   eclipse.ini如下:   -startupplugins/org.eclipse.equinox.launcher_1.2.0.v2 ...