算法导论的一个习题,使用一个存储空间来表示双向链表的prev next两个指针,存储这两个指针的异或。原理是“异或运算符合交换律、结合律”
这种方式最大好处是节省存储空间,而且可以在O(1) 的时间内反序链表。链表头结点需要保存第一个结点的指针,如此才可能遍历链表
struct xor_node {
void *np;
union {
int key;
struct xor_node *head_next; /* next node of the head */
};
};
链表结点结构,即可以表示链表中间结点,又可以表示链表头结点。如果需要反序链表时,直接将头结点的head_next 域指向最后一个结点即可
struct xor_node* xor_list_search(struct xor_node *head, int key, struct xor_node **prev_pp)
{
struct xor_node *next = NULL, *p = NULL, *prev = NULL;
for (p = head->head_next;p != NULL;p = next) {
if (p->key == key) {
*prev_pp = prev;
break;
}
next = (void *)((long)p->np ^ (long)prev);
prev = p;
}
return p;
}
链表search 函数,返回key对应的结点指针及基prev 指针void xor_list_add(struct xor_node *head, struct xor_node *node)
{
struct xor_node *next = head->head_next;
node->np = next;
head->head_next = node;
if (next) {
next->np = (void *)((long)(next->np) ^ (long)node);
head->np = (void *)((long)head->np ^ (long)next ^ (long)node);
}
}
链表结点添加函数,添加到链表头static void __xor_list_del(struct xor_node *head, struct xor_node *node, struct xor_node *prev)
{
struct xor_node *next;
next = (struct xor_node *)((long)node->np ^ (long)prev);
if (prev && next) {
prev->np = (void *)((long)prev->np ^ (long)node ^ (long)next);
next->np = (void *)((long)next->np ^ (long)node ^ (long)prev);
}
else if (prev) {
prev->np = (void *)((long)prev->np ^ (long)node);
head->np = (void *)((long)head->np ^ (long)node ^ (long)prev);
}
else if (next) {
next->np = (void *)((long)next->np ^ (long)node);
head->np = (void *)((long)head->np ^ (long)node ^ (long)next);
head->head_next = next;
}
else {
head->np = NULL;
head->head_next = NULL;
}
}
void xor_list_del(struct xor_node *head, struct xor_node *node)
{
struct xor_node *p, *prev;
p = xor_list_search(head, node->key, &prev);
if (p == NULL) {
printf("No such node for key(%d) in the list\r\n", node->key);
return;
}
__xor_list_del(head, node, prev);
}
链表结点删除函数,由于没有prev指针,因此需要首先获取删除结点的prev 结点,才能进行删除
这类链表虽然可以节省空间,但复杂度相对增大,search 操作的时间也较长,故使用上不方便,但作为思维锻炼还是相当有好处的

399

被折叠的 条评论
为什么被折叠?



