zoukankan      html  css  js  c++  java
  • 【数据结构(ywm版)】异或指针双向链表

    在《数据结构题集》中看到这种链表,实际上就是把一般的双向链表的next和prior两个指针通过异或运算合并为一个指针域来存储,每个结点确实可以减少一个指针的空间,但会带来取指针值时运算的开销。

    实现的时候,先搞清双向链表,把握异或指针域的原理公式,然后从双向链表出发进行转换即可。

    1 typedef struct XorNode{ //结点的定义
    2     ElemType data;
    3     struct XorNode* LRPtr;
    4 }XorNode, *XorPointer;
    5 
    6 typedef struct{//无头结点的异或指针双向链表
    7     XorPointer Left, Right; //只保存指向首、末结点的指针
    8 }XorList;

    每个结点的指针域存的是它的前驱和后继的异或值,即 LRPtr = prior ^ next,指针异或运算本质上就是整型的内存地址的按位异或。

    1 //指针异或函数,注意指针变量不支持^运算,需要强转为整型(内存地址,长度与机器有关,C将之封装为size_t型)
    2 XorPointer XorP(XorPointer p, XorPointer q){
    3     size_t x = (size_t)p;
    4     size_t y = (size_t)q;
    5     return (XorPointer)(x^y);
    6 }

    这相当于把前驱和后继的指针编码到一个指针域中了,那么如何解码呢,只凭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 值超过表长而导致的“兜圈子”;在边界操作时注意修改首末元素指针。

     1 Status CreateList(XorList& L, int n){
     2 //头插法建表,无头结点,入口条件:n>=1
    3 n--; 4 XorPointer p; 5 p = (XorPointer)malloc(sizeof(XorNode)); 6 L.Left = L.Right = p; 7 p->data = n; 8 p->LRPtr = XorP(p, p); 9 while(n--){ 10 p = (XorPointer)malloc(sizeof(XorNode)); 11 p->data = n; 12 p->LRPtr = XorP(L.Right, L.Left); 13 L.Left->LRPtr = XorP(p, XorP(L.Right, L.Left->LRPtr)); 14 L.Right->LRPtr = XorP(XorP(L.Right->LRPtr,L.Left),p); 15 L.Left = p; 16 } 17 } 18 19 Status Insert(XorList& L, int i, ElemType e){ 20 //在第i个位置前插入结点e(i的合法值为1~表长+1) 21 //由于无头结点,故判断表长是否够i,要通过计步变量k 22 XorPointer p = L.Left, q = L.Right; 23 int k = 1; 24 while(p!=L.Right && k<i){ //p指向i, q指向i-1;保证至多扫描一遍后退出 25 XorPointer t = p; 26 p = XorP(q, p->LRPtr); 27 q = t; 28 k++; 29 } 30 if(k+1<i) return ERROR; //表长不够i-1 31 if(k+1==i){p = L.Left; q = L.Right;} //插到表长+1的位置,即最后一个元素之后 32 XorPointer s = (XorPointer)malloc(sizeof(XorNode)); 33 s->data = e; 34 s->LRPtr = XorP(q, p); 35 q->LRPtr = XorP(XorP(q->LRPtr, p), s); 36 p->LRPtr = XorP(s, XorP(q, p->LRPtr)); 37 if(i==1) L.Left = s; 38 if(i==k+1) L.Right = s; 39 return OK; 40 } 41 42 Status Delete(XorList& L, int i, ElemType& e){ 43 //删除第i个位置的元素,用e返回其值(i的合法值为1~表长) 44 XorPointer p = L.Left, q = L.Right; 45 int k = 1; 46 while(p!=L.Right && k<i){ //p指向i, q指向i-1 47 XorPointer t = p; 48 p = XorP(q, p->LRPtr); 49 q = t; 50 k++; 51 } 52 if(k<i) return ERROR; //表长不够i 53 if(p==L.Right) L.Right = q; //删除最后一个结点 54 e = p->data; 55 XorPointer m = XorP(q, p->LRPtr); //m暂存p的后继 56 q->LRPtr = XorP(XorP(q->LRPtr, p), m); 57 m->LRPtr = XorP(q, XorP(p, m->LRPtr)); 58 free(p); 59 if(i==1) L.Left = m; //删除第一个结点 60 return OK; 61 } 62 63 Status Traverse(XorList& L, void (*visit)(XorNode)){ 64 XorPointer p = L.Left, q = L.Right; 65 while(p != L.Right){ 66 visit(*p); 67 XorPointer t = p; 68 p = XorP(q,p->LRPtr); 69 q = t; 70 } 71 visit(*p); 72 return OK; 73 } 74 75 void print(XorNode xn){ 76 printf("[%d]",xn.data); 77 } 78 79 int main() 80 { 81 XorList l; 82 CreateList(l,10); 83 ElemType e; 84 if(Delete(l,5,e)) 85 Traverse(l,print); 86 return 0; 87 }
  • 相关阅读:
    Powershell数据处理
    Powershell About Active Directory Group Membership of a domain user
    Powershell About Active Directory Server
    Oracle Schema Objects——Tables——TableStorage
    Oracle Schema Objects——Tables——TableType
    English Grammar
    Oracle Database Documentation
    Oracle Schema Objects——Tables——Oracle Data Types
    Oracle Schema Objects——Tables——Overview of Tables
    What is Grammar?
  • 原文地址:https://www.cnblogs.com/helenawang/p/5179660.html
Copyright © 2011-2022 走看看