In-depth explanation of quick sorting of Single-Chain tables

Source: Internet
Author: User

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 Node smaller than the benchmark is placed in the left-side sublinked list, and the Child linked list placed on the right is larger than the benchmark. After scanning the sorted linked list, the node values of the left sub-linked list are smaller than the benchmark value, and the values of the right sub-linked list are greater than the benchmark value, and then insert the benchmark into the linked list, and serves as a bridge connecting two sub-linked lists. Then, the left and right sublists are recursively sorted to improve performance.
However, because a single-chain table cannot be stored randomly as an array, there are still some details that need attention in comparison with the fast sorting of Arrays:

1. Selection of pivot points. Because the K-th element cannot be randomly accessed, the head pointer of the linked list to be sorted can be obtained each time the pivot point is selected.
2. The traversal table method cannot traverse forward from the end of a single-chain table. Therefore, the two pointers are used to traverse forward and backward respectively,
In fact, you can traverse small elements to the left of a single-chain table. The specific method is:
1) define two pointers: pslow and pfast. pslow points to the header node of a single-chain table, and pfast points to the next node of the single-chain header node;
2) use pfast to traverse a single-chain table. Every time a single-chain table encounters an element smaller than the pivot point, pslow = pslow-> next and then exchange data with pslow.
3. Exchange data to directly exchange the Data Pointer pointing to the linked list, without switching the linked list Node itself.
The quick sorting of single-chain table based on the above idea is as follows:Copy codeThe Code is as follows :/**
** Quick sorting of Single-Chain tables
** Author: liuzhiwei
** Date: 2011-08-07
**/
# Include <iostream>
# Include <ctime>
Using namespace std;
// Single-chain table Node
Struct SList
{
Int data;
Struct SList * next;
};
Void bulid_slist (SList ** phead, int n) // pointer to the pointer
{
Int I;
SList * ptr = * phead;
For (I = 0; I <n; ++ I)
{
SList * temp = new SList;
Temp-> data = rand () % n; // generate a random number of n or less
Temp-> next = NULL;
If (ptr = NULL)
{
* Phead = temp;
Ptr = temp;
}
Else
{
Ptr-> next = temp;
Ptr = ptr-> next;
}
}
}
Void print_slist (SList * phead) // output linked list
{
SList * ptr = phead;
While (ptr)
{
Printf ("% d", ptr-> data );
Ptr = ptr-> next;
}
Printf ("\ n ");
}
Void my_swap (int * a, int * B)
{
Int temp;
Temp = *;
* A = * B;
* B = temp;
}
Void sort_slist (SList * phead, SList * pend) // sort the head pointer to phead and the end pointer to the pend linked list.
{
If (phead = NULL)
Return;
If (phead = pend)
Return;
SList * pslow = phead;
SList * pfast = phead-> next;
SList * ptemp = phead;
While (pfast! = Pend)
{
If (pfast-> data <phead-> data) // select the header node of the list to be sorted each time as the benchmark for partitioning.
{
Ptemp = pslow; // ptemp is always the frontend node of pslow.
Pslow = pslow-> next;
My_swap (& pslow-> data, & pfast-> data); // The pslow Pointer Points to a linked list composed of nodes smaller than the benchmark.
}
Pfast = pfast-> next;
}
My_swap (& pslow-> data, & phead-> data); // The pslow Pointer Points to the last node of the linked list consisting of nodes smaller than the benchmark, that is, the benchmark location, therefore, we need to exchange data with the benchmark (head node ).
Sort_slist (phead, pslow); // ptemp is the first node of the Left and Right Split points (benchmark ).
Sort_slist (pslow-> next, NULL); // the right part is a linked list consisting of nodes larger than the benchmark.
}
Void destroy_slist (SList * phead)
{
SList * ptr = phead;
While (ptr)
{
SList * temp = ptr;
Ptr = ptr-> next;
Delete temp;
}
}
Int main (void)
{
Srand (time (NULL ));
Printf ("Before sort single list \ n ");
SList * phead = NULL;
Bulid_slist (& phead, 100 );
Print_slist (phead );
Printf ("After sort single list \ n ");
Sort_slist (phead, NULL );
Print_slist (phead );
Destroy_slist (phead );
System ("pause ");
Return 0;
}

Method 2:
Select the first node of the linked list as the benchmark, and then compare it. If the node is smaller than the benchmark, it is placed in the sublinked list on the left. If the node is larger than the benchmark, it is placed in the sublinked list 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 knots in the left and right sublists, select a smaller number for Recursive quick sorting, and perform iterative sorting for a large number.
The variables used in the sorting function are as follows:Copy codeCode: 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 take a closer look at the program. When left_walk is initialized to head, the first execution of * left_walk directs the head to the Start Node of the left-side 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, * 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 complete code is as follows:

Copy codeThe Code is as follows: # include <stdio. h>
# Include <stdlib. h>
# Include <time. h>
// Linked list Node
Struct node
{
Int data;
Struct node * next;
};
// Fast sorting function of the linked list
Void QListSort (struct node ** head, struct node * h );
// Print the linked list
Void print_list (struct node * head)
{
Struct node * p;
For (p = head; p! = NULL; p = p-> next)
{
Printf ("% d", p-> data );
}
Printf ("\ n ");
}
Int main (void)
{
Struct node * head = NULL;
Struct node * p;
Int I;
/**
* Initialize the linked list
*/
Srand (unsigned) time (NULL ));
For (I = 1; I <11; ++ I)
{
P = (struct node *) malloc (sizeof (struct node ));
P-> data = rand () % 100 + 1;
If (head = NULL)
{
Head = p;
Head-> next = NULL;
}
Else
{
P-> next = head-> next;
Head-> next = p;
}
}
Print_list (head );
Printf ("--------------------------------- \ n ");
QListSort (& head, NULL );
Print_list (head );
System ("pause ");
Return 0;
}
Void QListSort (struct node ** head, struct node * end)
{
Struct node * right;
Struct node ** left_walk, ** right_walk;
Struct node * handle, * old;
Int count, left_count, right_count;
If (* head = end)
Return;
Do {
Head = * head;
Left_walk = head;
Right_walk = & right;
Left_count = right_count = 0;
// Take the first node as the benchmark for comparison, smaller than the benchmark in the left-side sub-linked list,
// Sublinked list on the right that is greater than the benchmark
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 and continue the comparison.
++ Right_count;
* Right_walk = old;
Right_walk = & (old-> next );
}
}
// Merge the linked list
* Right_walk = end; // end the right linked list.
* Left_walk = cursor; // place the benchmark in the correct position.
Combine-> next = right; // combines the linked list
// Sort small sub-linked lists quickly, while large sub-linked lists are sorted iteratively.
If (left_walk> right_walk)
{
QListSort (& (response-> next), end );
End = begin;
Count = left_count;
}
Else
{
QListSort (head, cursor );
Head = & (response-> next );
Count = right_count;
}
}
While (count> 1 );
}

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.