In general, to implement a circular doubly linked list, each node needs to have two chain domains: precursor and successor. Now the question is: how to design a circular table, so that each node of the table contains only one link field and can effectively find it in two directions. This article will give a realization way.
First, before giving, you need to understand an interesting operation, which is the XOR operation . The truth table for XOR operations is as follows:
A |
B |
A^b |
0 |
0 |
0 |
0 |
1 |
1 |
1 |
0 |
1 |
1 |
1 |
0 |
By the nature of the XOR can be known, for any one binary number A, there is A^a = 0. Taking advantage of this nature, consider the following classic example: Implementing the exchange of two integers
void swap (intint *y) { *y = *x ^ *y; /* */ *x = *x ^ *y; /* */ *y = *x ^ *y; /* */}
Why does the above code allow two-number exchange? To call swap (&a, &b) as an example, the following table gives an explanation:
Step |
*x |
*y |
Initialization |
A |
B |
Step 1 |
A |
A^b |
Step 2 |
A^a^b=0^b=b |
A^b |
Step 3 |
B |
B^a^b=0^a=a |
Yes, as can be known through the above table, using A^a = 0, we can do this "tall" to achieve two number of exchanges (in fact, this mode of exchange does not have a performance advantage). But we can use it to understand the XOR operation. We can summarize the formula A^a^b = B by the above table. What are the implications of this article for solving the problem?
In order to make each node of the table contain only one chain field and be able to find it in two directions effectively, we can get the precursor of the node's chain domain and the prev of the successor next, and then use the nature of the XOR operation, which can be obtained (prev ^ next) ^ next = prev; (prev ^ next) ^ prev = next. We can think of an XOR domain as a special lock, with two different keys, with the key next to open the door of the precursor prev, and the key prev to open the next door.
The ring table is designed as follows:
struct Node *position;typedef Position ringlist; struct node{ int data; Position Prevxornext; // precursors and successors of the XOR };
When creating a ring linked list, first set up a head node RL, and affirm that the node pointer prev and Next, in order to let the head node's chain domain can directly point to the first node FIRSTP, the prev is initialized to 0, because 0 and a value of the XOR does not change the value, so rl-> Prevxornext = Prev^next = 0^next. However, note that the position type can not directly do the XOR operation, need to be strong to the INT type calculation results and then strong to position type. (because position is a struct pointer, the pointer is stored as a four-byte, 32-bit, which can be considered an int in essence)
Create the ring list function as follows:
Ringlist createringlist (Position *prevnode, Position *nextnode) {ringlist RL=NewNode;//Head knot Point intx; Position P=RL; Position prev=0;//The XOR of the initial head node is equivalent to the nextPosition Next; Position FIRSTP= NULL, SECONDP =NULL; intn =0; while(SCANF ("%d", &x)! =EOF) {N++; Position NEWP=NewNode; if(n = =1) FIRSTP=NEWP; if(n = =2) SECONDP= NEWP;//saving pointers to the second node makes it easy to update the first node laterNewp->data =x; Next=NEWP; P->prevxornext = (Position) ((int) Prev ^ (int) next); Prev=p; P=NEWP; } //Associate the chain field of the tail pointer with the first nodeP->prevxornext = (Position) ((int) Prev ^ (int) FIRSTP); //after the ring is formed, update the chain field of the first nodeFirstp->prevxornext = (Position) ((int) p ^ (int) SECONDP); *prevnode =p; *nextnode =SECONDP; returnRL;}
If we want to find the successor of p node, we just need to save the precursor prev of P node before temporarily, then P = p->prevxornext^prev, according to the nature of the XOR operation, the current P is the successor of P. Similarly, if you want to find a precursor to the P-node, you only need to temporarily save the subsequent next of the P-node, then P = p->prevxornext^next, at which point P is the precursor of the previous P-prev.
The clockwise access function is as follows:
voidclockwise (ringlist RL, Position prev2) {Position FIRSTP= rl->Prevxornext; Position Prev1=FIRSTP; printf ("%d", firstp->data); Position cur= (Position) ((int) Prev1->prevxornext ^ (int) (Prev2)); while(cur! =FIRSTP) {printf ("%d", cur->data); Prev2=Prev1; Prev1=cur; Cur= (Position) ((int) Prev1->prevxornext ^ (int) (Prev2)); } printf ("\ n");}
The counter-clockwise access function is as follows:
voidanticlockwise (ringlist RL, Position next2) {Position FIRSTP= rl->Prevxornext; Position Next1=FIRSTP; printf ("%d", firstp->data); Position cur= (Position) ((int) Next1->prevxornext ^ (int) (NEXT2)); while(cur! =FIRSTP) {printf ("%d", cur->data); Next2=Next1; Next1=cur; Cur= (Position) ((int) Next1->prevxornext ^ (int) (NEXT2)); } printf ("\ n");}
Here's the full code:
#include <cstdio>using namespaceStd;typedefstructNode *position;typedef Position ringlist;structnode{intdata; Position Prevxornext;};voidClockwise (Ringlist RL, Position prev2);//ClockwisevoidAnticlockwise (ringlist RL, Position next);//Counter-clockwiseRinglist createringlist (Position *prev, Position *next);//creating a ring linked listintMain () {Position prev, next; Ringlist RL= Createringlist (&prev, &next); printf ("Clockwise:"); Clockwise (RL, prev); printf ("counter-clockwise:"); Anticlockwise (RL, next); return 0;} Ringlist createringlist (Position*prevnode, Position *nextnode) {ringlist RL=NewNode;//Head knot Point intx; Position P=RL; Position prev=0;//An xor of the initial head node is equivalent to next, and 0 xor or a number equals its ownPosition Next; Position FIRSTP= NULL, SECONDP =NULL; intn =0; while(SCANF ("%d", &x)! =EOF) {N++; Position NEWP=NewNode; if(n = =1) FIRSTP=NEWP; if(n = =2) SECONDP= NEWP;//saving pointers to the second node makes it easy to update the first node laterNewp->data =x; Next=NEWP; P->prevxornext = (Position) ((int) Prev ^ (int) next); Prev=p; P=NEWP; } //Associate the chain field of the tail pointer with the first nodeP->prevxornext = (Position) ((int) Prev ^ (int) FIRSTP); //after the ring is formed, update the chain field of the first nodeFirstp->prevxornext = (Position) ((int) p ^ (int) SECONDP); *prevnode =p; *nextnode =SECONDP; returnRL;}voidclockwise (ringlist RL, Position prev2) {Position FIRSTP= rl->Prevxornext; Position Prev1=FIRSTP; printf ("%d", firstp->data); Position cur= (Position) ((int) Prev1->prevxornext ^ (int) (Prev2)); while(cur! =FIRSTP) {printf ("%d", cur->data); Prev2=Prev1; Prev1=cur; Cur= (Position) ((int) Prev1->prevxornext ^ (int) (Prev2)); } printf ("\ n");}voidanticlockwise (ringlist RL, Position next2) {Position FIRSTP= rl->Prevxornext; Position Next1=FIRSTP; printf ("%d", firstp->data); Position cur= (Position) ((int) Next1->prevxornext ^ (int) (NEXT2)); while(cur! =FIRSTP) {printf ("%d", cur->data); Next2=Next1; Next1=cur; Cur= (Position) ((int) Next1->prevxornext ^ (int) (NEXT2)); } printf ("\ n");}
View Code
The results of the operation are as follows:
Reference: "In-depth understanding of computer systems"
(digression: Today seems to be a spontaneous programmer's Day: 1024, although he is a quasi-programmer, but also wish their holiday happy ~hh~. Hopefully, this holiday will be a real certainty ('? ') before it becomes a real programmer. ))
Two-way traversal of circular linked lists using nodes with only one chain domain