XOR Linked list https://hackmd.io/@sysprog/linux2023-quiz1#測驗-3 Standard Doubly linked list ```c struct list_head { struct list_head *prev; struct list_head *next; }; struct item { uint16_t i; struct list_head list; }; ``` 標準的 doubly linked list node 裡有 prev, next 的位址。 但有另一種 XOR linked list 用一個 link 可以表達雙向 linked list XOR Linked List ## 複習基本的 XOR 操作 ``` A^A = 0 A^0 = A A^B = B^A A = A^B^B ``` ## Example ``` add 1 2 3 4 data HAT CAT EAT BAT link 2 2 6 3 ``` ``` 2 = 1^3 link(CAT) = add(HAT) ^ add(EAT) 6 = 2^4 link(EAT) = add(CAT) ^ add(BAT) 2 = 1^ 3 ``` 要往下一格移動時,我們需要**前一格**在哪和**這一格**的位置。例如我們現在在 HAT (1), 已知前一格是 (0),那麼下一格就是 `link(1) XOR 0 = 2 XOR 0 = 2`,也就是 CAT。繼續,現在位於 CAT (2),前一格在 (1),於是下一格就是 `link(2) XOR 1 = 2 XOR 1 = 3`,亦即 EAT,依此類推。只要當找出來的下一格是 (0) 就結束。 ``` link(CAT) = add(HAT) ^ add(EAT) add(EAT) = add(HAT) ^ add(HAT) ^ add(EAT) = link(CAT) ^ add(EAT) ``` ## 實作 考慮一個 xor_list_t 代表整條 list ```c typedef struct _xor_list_struct { xor_node_t head, tail; uint32_t count; } xor_list_t; ``` xor_node_t 代表單一個 node ```c typedef struct _xorlist_node { struct _xorlist_node *cmp;//just one pointer } xor_node_t; ``` 有趣的是,這裡的用來放在 list 的 node 跟存資料的 node 會分成兩個資料結構 ```c struct test_node { int value; xor_node_t xornode; }; ``` ### traverse ```c //rp previous //rn next #define xorlist_for_each(node, rp, rn, list) \ for (rp = &(list)->head, node = rp->cmp; node != &(list)->tail; \ rn = address_of(rp, node->cmp), rp = node, node = rn) ``` ```c xor_list_t list; xor_node_t *real_prev, *real_next, *node; int i = 0; printf("xorlist_for_each test\n"); xorlist_for_each(node, real_prev, real_next, &list) { printf("node [%d] %d\n", i++, container_of(node, struct test_node, xornode)->value); } ``` ```graphviz digraph list { rankdir=LR; node[shape=record, style=bold]; null[label=null][shape=plaintext] subgraph cluster_0 { node [shape=record]; head [label="{head}"]; tail [label="{tail}"]; count [label="count"][shape=plaintext]; style=bold; label=list } subgraph cluster_1 { label="new node 1" value[label=value] xornode[label="<label>xornode|{<cmp>cmp}" ] } subgraph cluster_2 { label="new node 2" value2[label=value] xornode2[label="<label>xornode|{<cmp>cmp}" ] } head->xornode:label xornode:cmp->xornode2:label xornode2:cmp->null } ``` ```c for (int i = 0; i < 1000; i++) { struct test_node *new = malloc(sizeof(struct test_node)); xornode_init(&new->xornode); new->value = i; xorlist_add(&list, &new->xornode); } ``` ### insert ```c // add n to list head int xorlist_add(xor_list_t *list, xor_node_t *n) { if (!n) return ENOMEM; xor_node_t *real_prev = &list->head; xor_node_t *real_next = real_prev->cmp; // real_prev->cmp = 0 ^ real_next = real_next real_prev->cmp = n; //real_prev->cmp = 0 ^ n n->cmp = XOR_COMP(real_prev, real_next); real_next->cmp = XOR_COMP(n, XOR_COMP(real_prev, real_next->cmp)); //XOR_COMP(real_prev, real_next->cmp) would be B->next list->count++; return 0; } ``` ```graphviz digraph list { rankdir=LR; node[shape=record, style=bold]; head[label="A|{<cmp>cmp=B}"]; tail[label="B|{<cmp>cmp=C}"]; node1[label="C|{<cmp>cmp=A ^ B}"] n[label="n"][shape=plaintext] rn[label="real_next"][shape=plaintext] rp[label="real_prev"][shape=plaintext] head:cmp->node1:cmp[dir=both] node1:cmp->tail:cmp[dir=both] n->node1 rn->tail rp->head } ``` ### delete 給定要刪除節點的前一個節點 n 、要刪除的節點 target ```c int xorlist_del(xor_list_t *list, xor_node_t *n, xor_node_t *target, int (*delete_func)(xor_node_t *)) { assert(list && n && target && delete_func); assert(&list->head != target && &list->tail != target); xor_node_t *nn = address_of(target, n->cmp);//上上個節點 xor_node_t *an = address_of(n, target->cmp);//下個節點 xor_node_t *ana = address_of(target, an->cmp);//下下個節點 n->cmp = XOR_COMP(nn, an); an->cmp = XOR_COMP(n, ana); delete_func(target); list->count--; return 0; } ``` ![image](https://hackmd.io/_uploads/SkXqrXZuT.png) ``` /* 0 1 2 3 4 5 6 7 8 */ 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 ``` $A = \int_{-r}^{r}\sqrt{r^2 - x^2}dx$