算法导论10.2.8

来源:互联网 发布:rs232端口是什么意思 编辑:程序博客网 时间:2024/04/29 21:17

一、题目

说明如何对每个元素仅用一个指针np[x](而不是两个指针next和prev)来实现双链表。假设所有指针值都是k位的整型数,且定义np[x] = next[x] XOR prev[x],即next[x]和prev[x]的k位异或(NIL用0表示)。注意要说明访问表头所需的信息,以及如何实现在该表上的SEARCH、INSERT和DELETE操作。如何在O(1)时间内实现这样的表。


二、思路

np[x] = next[x] XOR prev[x],根据异或的性质,next[x] = np[x] XOR prev[x],prev[x] = next[x] XOR np[x],只要知道这个结点的下一个结点的地址,就能求出它上一个结点的地址,或者,只要知道这个结点上一个结点的位置,就知道求出它的下一个结点的位置

在链表中定义一个头结点,这个结点的位置是已知的,根据上文的结论,就可以依次遍历链表中的每个结点,进行于SEARCH、INSERT和DELETE操作了

其中应注意的要点是:

1.先建立一个链表L,其中表头存放着一个初始结点node head,这是第一个结点,隐含着head.prev=0,即head.np=head.prev XOR head.next=head.next。这一点十分重要,它说明了head.np=head.next恒成立。说明我们从一开始就已经知道head.next的地址,即第一个元素地址

2应注意异或的性质:A XOR A=0,即两个相同的数做异或,它们的结果一定为0.这一点在求各个结点的np时特别有用,还有A XOR B=C,则有B=A XOR C和C =BXOR A,即三个数可以通过两两异或得出第三个数。

3在插入中,新插入的点A的next结点和head的下一个结点相同,这一点我思考了好久才明白,这是为什么呢?因为如果链表一开始是空,则head.next=null,此时A插入到表头,则A.next也是null,相等。若一开始链表不为空,假设head.next指向B,现在新插入一个A,那么A.next也必然是指向B

三、代码

 

[cpp] view plaincopy
  1. #include <iostream>  
  2. #include <string>  
  3. using namespace std;  
  4.   
  5. //结点  
  6. struct node  
  7. {  
  8.     int key;//值  
  9.     unsigned int np;//指针,地址是32位的,所以要用无符号整数表示  
  10.     node(int k):key(k),np(0){}  
  11. };  
  12. //链表  
  13. struct list  
  14. {  
  15.     node head;//头结点,作为哨兵,用于寻找第一个结点  
  16.     list():head(0){}  
  17. };  
  18. //插入操作  
  19. void Insert(list *l, int k)  
  20. {  
  21.     //生成一个新的结点  
  22.     node *A = new node(k);  
  23.     //要插入到链表的第一个位置,即head->next处  
  24.     //A->next是head->next,其地址为l->head.np,A->prev是head,其地址为(unsigned int)(&(l->head))  
  25.     //A->np是A->next ^ A->prev  
  26.     A->np = l->head.np ^ (unsigned int)(&(l->head));  
  27.     //若原链表不为空,则要修改原head->next结果的指针,因为它的prev发生了改变  
  28.     node *p = (node*)l->head.np;  
  29.     if(p)  
  30.     {  
  31.         //NewNp = OldNp ^ OldNext ^ OldPrev ^ NewNext ^ NewPrev;  
  32.         //在这里,只是p->prev有改动,p->next不变,因此简化为NewNp = OldNp ^ OldPrev ^ NewPrev;  
  33.         //OldPrev是Head,其地址为(unsigned int)(&(l->head)),NewPrev是新结点A,其地址为(unsigned int)A  
  34.         unsigned int temp = p->np;  
  35.         temp = temp ^ (unsigned int)A ^ (unsigned int)(&(l->head));  
  36.         p->np = temp;  
  37.     }  
  38.     l->head.np = (unsigned int)A;  
  39. }  
  40. //输出链表  
  41. void Print(list *l)  
  42. {  
  43.     //找到第一个结点的位置,因为Head->prev=0,Head->next=Head->np,直接可以得到第一个结点的位置  
  44.     unsigned int p = l->head.np, q;  
  45.     //q表示为p->prev结点的位置  
  46.     q = (unsigned int)(&(l->head));  
  47.     //把p转换为指针  
  48.     while((node*)p)  
  49.     {  
  50.         //输出  
  51.         cout<<((node*)p)->key<<' ';  
  52.         //p指向下一个元素  
  53.         unsigned int t = p;  
  54.         p = ((node*)p)->np ^ q;  
  55.         q = t;  
  56.     }  
  57.     cout<<endl;  
  58. }  
  59. //删除  
  60. void Delete(list *l, int k)  
  61. {  
  62.     //依次遍历每个元素,遍历方法同Search   
  63.     unsigned int p = l->head.np, q;  
  64.     q = (unsigned int)(&(l->head));  
  65.     while((node*)p)  
  66.     {  
  67.         if(((node*)p)->key == k)  
  68.             break;  
  69.         unsigned int t = p;  
  70.         p = ((node*)p)->np ^ q;  
  71.         q = t;  
  72.     }  
  73.     //p是待删除元素的地址,q是待删除元素的上一个元素的地址,r是待删除元素的下一个元素的地址  
  74.     if((node*)p == NULL)  
  75.         return;  
  76.     int r = ((node*)p)->np ^ q;  
  77.     //修改q->next和修改r->prev,修改方法与INSERT中的修改方法相似  
  78.     ((node*)q)->np = ((node*)q)->np ^ p ^ r;  
  79.     if((node*)r != NULL)  
  80.         ((node*)r)->np = ((node*)r)->np ^ p ^ q;  
  81.     //删除p指向的结点  
  82.     delete (node*)p;  
  83. }  
  84. int main()  
  85. {  
  86.     string str;  
  87.     list *L = new list;  
  88.     int x;  
  89.     while(1)  
  90.     {  
  91.         cin>>str;  
  92.         if(str == "P")  
  93.         {  
  94.             Print(L);  
  95.         }  
  96.         else if(str == "I")  
  97.         {  
  98.             x = rand() % 100;  
  99.             cout<<x<<endl;  
  100.             Insert(L, x);  
  101.         }  
  102.         else if(str == "D")  
  103.         {  
  104.             cin>>x;  
  105.             Delete(L, x);  
  106.         }  
  107.     }  
  108.     return 0;  
  109. }  
原创粉丝点击