Today, when I learned how to use algorithms for programmers, I saw the quick sorting of Single-Chain tables. At first glance, I felt that the program had a lot of problems, but after I had a good taste, I found that the program design was extremely clever. At the same time, I felt that my C language pointer knowledge was not strong, especially pointer knowledge.
The basic idea of fast sorting of a single-chain table is the same as that of an array. It is also based on division, but there is a big difference: A single-chain table does not support access based on the bottom object. Therefore, the linked list to be sorted is split into two sublinked lists. For the sake of simplicity, select the first node of the linked list as the benchmark, and then compare it. The sublinked list is placed on the left of the larger node than the benchmark, and the sublinked list is placed on the right. After scanning the sorted linked list, the node values of the left-face linked list are smaller than the benchmark values, the values of the right-side sublinked list are greater than the benchmark values, and then the benchmark is inserted into the linked list, and serves as a bridge connecting two sub-linked lists. Then, based on the number of nodes in the left and right sublists, select a smaller value for Recursive fast sorting, and sort the number of nodes that are larger in the descending waiting order to improve performance.
The variables used in the sorting function are as follows:
Struct node * right; // The first node of the sub-linked list on the right
Struct node ** left_walk, ** right_walk; // as a pointer, add the node to the corresponding sublinked list
Struct node * cursor, * old; // cursor is the benchmark, and old is the pointer to the linked list to be sorted in a loop.
The core code is as follows:
For (old = (* head)-> next; old! = End; old = old-> next ){
If (old-> data <strong-> data) {// less than the benchmark, add it to the sublinked list on the left and continue the comparison.
++ Left_count;
* Left_walk = old; // Add the node to the linked list on the left,
Left_walk = & (old-> next );
} Else {// greater than the benchmark, add it to the sublinked list on the right to continue the comparison.
++ Right_count;
* Right_walk = old;
Right_walk = & (old-> next );
}
}
The head type is struct node **. It points to the head of the linked list, and the end type points to the end of the linked list. It can be NULL. This program focuses on the usage of pointer, * left_walk is a pointer to a node. Clearly, * the value of left_walk is the memory address of the node. In fact, there is also a node address, that is to point to the next domain of the node, so we can simply think that * left_walk = old is to change the next domain of the node pointing to the node to the old address of the node, this may cause two situations: one is that * left_walk is originally directed to the old node, so that no change is made, the other is to change * right_walk to the next field of the previous node of the node, so that it points to the back node, skipping several nodes in the middle, however, this will not cause any problems, because the nodes in the linked list are either added to the sublinked list on the left or to the sublinked list on the right, and node loss will not occur.
The above problems are illustrated below:
Assume that the values of the linked list are 5, 2, 4, 6, and 1 at a time. According to the program, head = left_walk points to a node with a value of 5, old points to a node with a value of 2, and 2 is smaller than 5. Therefore, add the child linked list between 2 and the left, * left_walk = old, we know that * left_walk points to the first node. In this way, the head pointer value is changed so that it points to the second node. Then left_walk moves backward, old moves backward, and 4 is also less than 5, so proceed with the above operation, but this is * The left_walk and old point to the same node, without causing any changes, left_walk and old move back, 6 is greater than 5, then the difference will appear, to add it to the sub-linked list on the right, it is * right_walk = old. In fact, the first test of right_walk is "& right", which is equivalent to "Right = old, that is, the node currently pointed to by old is the first node of the sub-linked list on the right, and all nodes later than the benchmark must be added to this node and always added to the end. At this time, right_walk and old move back. If 1 is less than 5, it should be added to the left-side sub-linked list, * left_walk = old. At this time, * left_walk points to 6, therefore, the statement is used to change the next value of node 4 and change it to the address of Node 1. In this way, node 6 is decoupled from the original linked list, and then move left_walk and old to node 9, it should be added to the sub-linked list on the right. * right_walk points to 1, so 9 nodes are added to the back of 6 nodes.
This is the basic sorting process, but there is a problem that needs to be understood, for example, there are nodes in turn struct node * a, * B, * c, node ** p, p = & B. If * p = c is set at this time, the actual result is a-> next = c; we know that this is equivalent to the value of the next field of. P is just a pointer. It is a pointer to the address of the node pointed to by B, so how can we change the * p value to the next OF a (this can be verified by a program )? In fact, this is not the case. Let's look at the program. left_walk is initialized to head, so the first execution of * left_walk is to point the head to the Start Node of the Left linked list, then left_walk is assigned as & (old-> next). This sentence is interesting. Let's take a look at the situation when * left_walk = old is executed below, * left_walk = old is equivalent to * & (old-> next) = old, that is, old-> nex = old, however, the old value may not necessarily be the node pointed to by old-> next. It should be that left_walk and right_walk both point to their old nodes, but they are different.
The algorithm is not complete here. This is just a division, where the benchmark is placed in the correct position and we have to continue, but the following is relatively simple, it is a sublinked list with a relatively small number of recursive sorting nodes.
The overall code is as follows:
View plaincopy to clipboardprint?
01 ./**
02. * fast sorting of Single-Chain tables
03. * author: blue
04. * data: 2010-4-6
05 .*/
06.
07. # include <stdio. h>
08. # include <stdlib. h>
09. # include <time. h>
10. // linked list Node
11. struct node {
12. int data;
13. struct node * next;
14 .};
15. // fast sorting function of the linked list
16. void QListSort (struct node ** head, struct node * head );
17. // print the linked list
18. void print_list (struct node * head ){
19. struct node * p;
20. for (p = head; p! = NULL; p = p-> next ){
21. printf ("% d", p-> data );
22 .}
23. printf ("/n ");
24 .}
25. int main (void ){
26. struct node * head;
27. struct node * p;
28. int I = 0;
29 ./**
30. * initialize the linked list
31 .*/
32. head = (struct node *) malloc (sizeof (struct node ));
33. head-> next = NULL;
34. head-> data = 0;
35. srand (unsigned) time (NULL ));
36. for (I = 1; I <11; ++ I ){
37. p = (struct node *) malloc (sizeof (struct node ));
38. p-> data = rand () % 100 + 1;
39. p-> next = head-> next;
40. head-> next = p;
41 .}
42.
43. print_list (head );
44. printf ("---------------------------------/n ");
45. QListSort (& head, NULL );
46. print_list (head );
47. return 0;
48 .}
49.
50. void QListSort (struct node ** head, struct node * end ){
51. struct node * right;
52. struct node ** left_walk, ** right_walk;
53. struct node * handle, * old;
54. Int count, left_count, right_count;
55. If (* head = end)
56. return;
57. Do {
58. Heads = * head;
59. left_walk = head;
60. right_walk = & right;
61. left_count = right_count = 0;
62. // take the first node as the benchmark for comparison, smaller than the benchmark in the left-side sub-linked list,
63. // sublinked list on the right that is greater than the benchmark
64. for (old = (* head)-> next; old! = End; old = old-> next ){
65. if (old-> data <strong-> data) {// smaller than the benchmark, add it to the sublinked list on the left and continue the comparison.
66. ++ left_count;
67. * left_walk = old; // Add the node to the linked list on the left,
68. left_walk = & (old-> next );
69.} else {// greater than the benchmark. Add it to the sublinked list on the right and continue the comparison.
70. ++ right_count;
71. * right_walk = old;
72. right_walk = & (old-> next );
73 .}
74 .}
75. // merged linked list
76. * right_walk = end; // end the right linked list.
77. * left_walk = benchmark; // place the benchmark in the correct position
78. merge-> next = right; // combines the linked list
79. // sort small sub-linked lists quickly, while large sub-linked lists are sorted iteratively.
80. if (left_walk> right_walk ){
81. QListSort (& (Future-> next), end );
82. end = begin;
83. count = left_count;
84.} else {
85. QListSort (head, cursor );
86. head = & (response-> next );
87. count = right_count;
88 .}
89.} while (count> 1 );
90 .}
This article from the CSDN blog, reproduced please indicate the source: http://blog.csdn.net/PinkRobin/archive/2010/04/06/5456094.aspx
This article from the CSDN blog, reproduced please indicate the source: http://blog.csdn.net/PinkRobin/archive/2010/04/06/5456094.aspx
This article from the CSDN blog, reproduced please indicate the source: http://blog.csdn.net/PinkRobin/archive/2010/04/06/5456094.aspx