异或形式的双向链表

算法导论的一个习题,使用一个存储空间来表示双向链表的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 操作的时间也较长,故使用上不方便,但作为思维锻炼还是相当有好处的

你可能感兴趣的:(算法导论相关)