Algorithm 循环异或链表?

Algorithm 循环异或链表?,algorithm,data-structures,linked-list,xor-linkedlist,Algorithm,Data Structures,Linked List,Xor Linkedlist,我在读关于XOR链表的书时,有一个问题浮现在我的脑海中,有可能有一个循环XOR链表吗?在我看来,即使我们以某种方式建立这样一个链表,在给定链表的头节点的情况下也不可能遍历它。例如,让链表包含3个节点:A、B和C | v A ---> B ---> C A->xor = B ^ C B->xor = A ^ C C->xor = A ^ B 因为在这种情况下,我们被赋予了列表的head,即A,我们将无法向前或向后移动,因为我们必须至少知道B或C中的一个才能移动。既

我在读关于XOR链表的书时,有一个问题浮现在我的脑海中,
有可能有一个循环XOR链表吗?
在我看来,即使我们以某种方式建立这样一个链表,在给定链表的头节点的情况下也不可能遍历它。例如,让链表包含3个节点:A、B和C

|
v
A ---> B ---> C

A->xor = B ^ C
B->xor = A ^ C
C->xor = A ^ B
因为在这种情况下,我们被赋予了列表的
head
,即
A
,我们将无法向前或向后移动,因为我们必须至少知道
B
C
中的一个才能移动。既然我们不能穿越它,我们也不能建造它


我的想法正确吗?还是我遗漏了什么?

事实上,您是对的,因为我们无法从
xor
链接检索任何指针值,所以无法遍历此列表

要使此列表成为可遍历的,最低要求是两条信息……例如,指向当前节点的指针和指向下一个(或上一个)节点的指针。然后您可以从
xor
链接检索所有信息

事实上,这正是政府所说的:

要从某个点开始沿任意方向遍历列表,您需要两个连续项的地址,而不仅仅是一个


这仍然比为每个节点存储两个指针便宜,因为每个节点只需要一个链接,加上当前和下一个(或上一个)节点的两个指针。

这很有趣!我写了一个小的循环XOR链表程序作为概念证明,这是可能的。1和2节点的边缘情况有点奇怪,但只要你在某个地方跟踪头部和尾部指针,其他一切都会正常。(我也知道这是一个有7年历史的线程,但我有同样的问题,发现这几乎是唯一提到的循环XOR链表)

#包含//用于malloc
#包括//用于printf
#包括//用于uintptr\t
类型定义结构s_列表t_列表;
结构s_列表
{
char*data;//包含一个字符串。
结构s_list*npx;//npx=previous XOR next
};
列表*创建元素(字符*数据,列表*npx)
{
t_列表*ret;
ret=malloc(sizeof(*ret));
ret->data=数据;
ret->npx=npx;
返回(ret);
}
t_列表*xor(t_列表*a,t_列表*b)
{
返回列表*)((uintpttr)a^(uintpttr)b);
}
无效插入(t\u列表**h,t\u列表**t,字符*数据)
{
t_list*last=*t;
t_list*first=*h;
t_列表*新,npx;
如果(!last&&!first)//没有节点,则填充第一个节点
{
new=create_elem(data,NULL);//self-XOR-self==NULL
*h=(*t=new));
}
否则,如果(last==first)//只有一个节点,请正确设置tail
*t=create_elem(data,NULL);//self-XOR-self==NULL
否则//多个节点,执行真正的添加
{
//创建一个npx=first-XOR-last的元素
//(将插入列表末尾)
新建=创建元素(数据,异或(第一个,最后一个));
//如果head或tail的npx==0,我们知道它是一个大小为2的列表,
//因此,每个上一个和下一个指针都是相同的。
//因此,如果它是一个大小为2的列表
//last->npx=新异或优先
//第一个->npx=新的异或最后一个
//否则
//last->npx=新异或(last->npx异或优先)
//第一->npx=新异或(第一->npx异或最后)
last->npx=xor(新的,(!last->npx | |!first->npx)?
第一个:xor(最后一个->npx,第一个));
第一个->npx=xor(新的,(!最后一个->npx | |!第一个->npx)?
last:xor(first->npx,last));
//为传递的地址设置新指针。
*h=第一;
*t=新的;
}
}
整数遍历(t_列表*h,t_列表*t)
{
t_list*cur=h;
t_list*last=t;
t_列表*tmp;
while(cur)
{
printf(“[%s]\n”,cur->data);
tmp=xor(当前->npx,最后);
last=cur;
cur=tmp;
如果(cur==h)
申报表(1);
}
申报表(1);
}
内部主(空)
{
字符s1[]=“测试!”;
char s2[]=“我的!”;
char s3[]=“函数!”;
字符s4[]=“For!”;
char s5[]=“geeksforgeks!”;
//我们需要跟踪头和尾指针,以便
//一切都很顺利。
//遍历将始终需要访问
//两个连续的指针。
表*头;
t_列表*尾部;
head=NULL;
tail=NULL;
插入(头部和尾部,s1);
插入(头和尾,s2);
插入(头部和尾部,s3);
插入件(头部和尾部,s4);
插入件(头部和尾部,s5);
横移(头、尾);
}

不可能用一个值遍历列表,但可以找到所有值 可以工作的遍历,在本例中,我们找到可以遍历树的所有b和c:

a=5
for b in range(0, 16): 
    print(a, b, a ^ b)

5 0 5
5 1 4
5 2 7
5 3 6
5 4 1
5 5 0
5 6 3
5 7 2
5 8 13
5 9 12
5 10 15
5 11 14
5 12 9
5 13 8
5 14 11
5 15 10

在范围(0,16):打印(a,b,a^b)中,这与b的
不同吗?
a=5
for b in range(0, 16): 
    print(a, b, a ^ b)

5 0 5
5 1 4
5 2 7
5 3 6
5 4 1
5 5 0
5 6 3
5 7 2
5 8 13
5 9 12
5 10 15
5 11 14
5 12 9
5 13 8
5 14 11
5 15 10