Three linear time sorting algorithms-C ++ implementation

Source: Internet
Author: User

Introduction

 


Note: because no public editor is enabled, it is convenient to use the following symbol to represent the time complexity:

 


Let's look at a theorem: In the worst case, any comparative sorting algorithm needs to perform a comparison of $ (nlgn) times. It can be proved by the decision tree model. For details, see section 8th of Introduction to algorithms.

This Theorem points out the lower bound of the time complexity of comparative sorting, that is, there is no less.

The three algorithms described below are not comparison-based sorting algorithms. They all make certain assumptions about the input data, that is, they take advantage of the characteristics of specific data.

 


I. Counting sorting

 


1. Problem description: assume that each of the n elements in the array is an integer ranging from 0 to k and sorted. K is a positive integer.

2. Basic Idea: For each input element x, the number of elements smaller than x in the array is determined by using the range of [0, k. Since x is a positive integer, you can directly place x in its position in the final output array.

3. Algorithm Description:

Input: A [1... n], input array; C [0... k], provide temporary storage area, initial value: 0 --- O (k)

Output: B [1... n], storing the sorting result


(1) obtain the input array A [] 1... in n], the value is equal to the number of elements in A [j] and is stored in the corresponding C [1... k]: C [A [I] = C [A [I] + 1 --- O (n)

(2) obtain the input array A [] 1... in n], the value is less than or equal to the number of elements in A [j], and is stored iteratively in the corresponding C [1... in k]: C [j] = C [J-1] + C [j] --- O (K)

(3) After the first two steps, the value in C [I] indicates the number of elements smaller than or equal to I, that is, the value of I in A [1... n] and store it in B [1... n] medium: B [C [A [j] = A [j], C [A [j] = C [A [j]-1 (there may be elements to be equal) --- O (n)

4. Time Complexity: O (k) + O (n) + O (k) + O (n). The total running time is @ (k + n ), in practice, when k = O (n), the running time is: @ (n ).

5. Algorithm Implementation:


[Cpp]
# Include <stdio. h>
Const int K = 5;
Const int N = 6;
Int input [N + 1] = {-1, 2, 3, 4, 2, 1, 5 };
Int output [N + 1];
Int count [K] = {0 };
 
Void print (int array [], int n)
{
For (int I = 1; I <= n; I ++)
{
Printf ("% d", array [I]);
}
Printf ("\ n ");
}
Void countSort (int input [], int output [], int n)
{
Int I;
For (I = 1; I <= n; I ++)
{// Equal to input [I]
Count [input [I] = count [input [I] + 1;
}
For (I = 1; I <= K; I ++)
{// Less ro equal to I
Count [I] = count [I-1] + count [I];
}
For (I = n; I> = 1; I --) // form large to small to make sorting stable
{
Output [count [input [I] = input [I];
Count [input [I] --;
}
}
 
Int main ()
{
CountSort (input, output, N );
Print (output, N );
Return 0;
}

# Include <stdio. h>
Const int K = 5;
Const int N = 6;
Int input [N + 1] = {-1, 2, 3, 4, 2, 1, 5 };
Int output [N + 1];
Int count [K] = {0 };

Void print (int array [], int n)
{
For (int I = 1; I <= n; I ++)
{
Printf ("% d", array [I]);
}
Printf ("\ n ");
}
Void countSort (int input [], int output [], int n)
{
Int I;
For (I = 1; I <= n; I ++)
{// Equal to input [I]
Count [input [I] = count [input [I] + 1;
}
For (I = 1; I <= K; I ++)
{// Less ro equal to I
Count [I] = count [I-1] + count [I];
}
For (I = n; I> = 1; I --) // form large to small to make sorting stable
{
Output [count [input [I] = input [I];
Count [input [I] --;
}
}

Int main ()
{
CountSort (input, output, N );
Print (output, N );
Return 0;
}

 

Ii. Base sorting

 


1. Problem description: given n d-digits, each digit may be in k and sorted. For example, four three-digit numbers: 123,367,124,756, n = 4, d = 3, and K value is 10.

2. Basic Idea: first sort by the number with the lowest valid bits and collect the results. Then, sort by the number with the lowest valid bits, collect the results, and so on. repeat this process, until all the d-digit numbers are sorted.

Let's take a look at the example (from introduction to algorithms 8.3, P100 ):

 
 


Note: the sorting of each bit must be a stable sorting; otherwise, the sorting may be incorrect. For example, when sorting the highest bits, the first 436 is in front of the first 457. Because the highest bits are 4, the highest bits of the two numbers in this sorting are equal. If it is not a stable sorting, the result 457 may be prefixed with 436, so the result is incorrect. Stable sorting ensures that 436 is still in front of 457 after completion.

3. Algorithm Description:

Input array: A [1... n]

RADIX-SORT (A, d)

For I <-1 to d

Do use a stable sort to sort array A on digit I // You can select count sorting.

4. Time Complexity: It can be seen from the count sorting in the middle that the sorting time for each bit is: @ (k + n). A total of d times are executed here, so the time complexity: @ (d * (k + n). When d is a constant and k = O (n), the base sorting has a linear running time: @ (n ). For more general and specific analysis, you can refer to the introduction to algorithms> 8.3, 8.4, and P101. The detailed analysis is as follows: how to break down each keyword into several digits and in those cases, the time complexity is the best. Here we will only introduce some conclusions and implementation methods.

5. Algorithm Implementation:


[Cpp]
# Include <stdio. h>
# Include <math. h>
Const int N = 7;
Const int D = 3;
Const int K = 10;
Int count [K] = {0 };
// Int input [N + 1] ={- 1,329,457,657,839,436,720,355 };
Int output [D + 1] [N + 1] ={{-1,329,457,657,839,436,720,355 }};
 
Void print (int array [], int n)
{
For (int I = 1; I <= n; I ++)
{
Printf ("% d", array [I]);
}
Printf ("\ n ");
}
Int getDigit (int number, int d)
{
If (d> D) return-1;
Return number % (int) pow (10, d)/(int) pow (10, D-1 );
}
Void countSort (int input [], int output [], int n, int d)
{
Int I;
Int digit;
For (I = 1; I <= n; I ++)
{
Digit = getDigit (input [I], d );
Count [digit] = count [digit] + 1;
}
For (I = 1; I <= K; I ++)
{
Count [I] = count [I-1] + count [I];
}
For (I = n; I> = 1; I --) // form large to small to make sorting stable
{
Digit = getDigit (input [I], d );
Output [count [digit] = input [I];
Count [digit] --;
}
}
Void initDataStruct (int count [])
{
For (int I = 0; I <K; I ++)
{
Count [I] = 0;
}
}
Void radixSort (int output [] [N + 1], int n, int d)
{
For (int I = 1; I <= d; I ++)
{
CountSort (output [I-1], output [I], n, I );
InitDataStruct (count );
}
}
 
Int main ()
{
RadixSort (output, N, D );
Print (output [D], N );
Return 0;
}

# Include <stdio. h>
# Include <math. h>
Const int N = 7;
Const int D = 3;
Const int K = 10;
Int count [K] = {0 };
// Int input [N + 1] ={- 1,329,457,657,839,436,720,355 };
Int output [D + 1] [N + 1] ={{-1,329,457,657,839,436,720,355 }};

Void print (int array [], int n)
{
For (int I = 1; I <= n; I ++)
{
Printf ("% d", array [I]);
}
Printf ("\ n ");
}
Int getDigit (int number, int d)
{
If (d> D) return-1;
Return number % (int) pow (10, d)/(int) pow (10, D-1 );
}
Void countSort (int input [], int output [], int n, int d)
{
Int I;
Int digit;
For (I = 1; I <= n; I ++)
{
Digit = getDigit (input [I], d );
Count [digit] = count [digit] + 1;
}
For (I = 1; I <= K; I ++)
{
Count [I] = count [I-1] + count [I];
}
For (I = n; I> = 1; I --) // form large to small to make sorting stable
{
Digit = getDigit (input [I], d );
Output [count [digit] = input [I];
Count [digit] --;
}
}
Void initDataStruct (int count [])
{
For (int I = 0; I <K; I ++)
{
Count [I] = 0;
}
}
Void radixSort (int output [] [N + 1], int n, int d)
{
For (int I = 1; I <= d; I ++)
{
CountSort (output [I-1], output [I], n, I );
InitDataStruct (count );
}
}

Int main ()
{
RadixSort (output, N, D );
Print (output [D], N );
Return 0;
}

 

Iii. Sort buckets

 


1. Problem description: assuming that an input array is generated in a random process, the elements are evenly distributed in the range [0, 1) and sorted.

2. Basic Idea: similar to the zipper method for resolving hash conflicts in a hash list, a bucket is essentially a linked list, and elements with the same keywords are placed in the same bucket. Since the elements in the input array are evenly and evenly distributed independently on [0, 1), many elements are generally not allocated to the same bucket. After the hash is complete, sort the elements in each bucket first, and then collect the elements in each bucket in order to obtain an ordered array.

3. Algorithm Description:

Input: A [1... n]; B [0... n-1]: Secondary array linked list, used for hashed Elements


Output: sorted A [1... n]

(1) divide the interval [0, 1) into n subintervals of the same size, or buckets (which can be achieved through the auxiliary array linked list B [0... N-1 ).

(2) It is known that the hash function is f (x) = floor (n * x) and rounded down, then the array element A [I] is allocated to the bucket (linked list) B [floor (n * A [I])] --- @ (n)

(3) sort the elements in each bucket B [I] (which can be inserted for sorting) --- n * O (2-1/n)

(4) Collect results from buckets in order.

4. Time Complexity: According to the algorithm description in step 3, except step (3), the time for other parts is O (n) in the worst case ). The knowledge of mathematical statistics can be obtained. In step (3), each bucket is sorted. The expected running time is 2-1/n. For details, see: in Section 8.4 of Introduction to algorithms, P103), the total time in step (3) is n * (2-1/n). Therefore, the expected running time of Bucket sorting is as follows: @ (n) + n * (2-1/n) = @ (n)

5. Algorithm Implementation:


[Cpp]
# Include <stdio. h>
# Include <math. h>
 
Const int N = 10;
Double input [N + 1] = {-1, 0.78, 0.17, 0.39, 0.26, 0.72, 0.94, 0.21 };
Typedef struct BucketNode
{
Double data;
Struct BucketNode * next;
} * BucketList, bucketNode;
BucketList bucketArr [N];
 
Void print (bucketList bucketArr [])
{
For (int I = 0; I <N; I ++)
{
BucketNode * pb = bucketArr [I];
While (pb)
{
Printf ("% e", pb-> data );
Pb = pb-> next;
}
Printf ("\ n ");

}
Printf ("\ n ");
}
 
Void initBucketList (bucketList bucketArr [])
{
For (int I = 0; I <N; I ++)
{
BucketArr [I] = NULL;
}
}
Bool insertBucketWithSorting (bucketList & bucket, double data)
{// Sorting while inserting
BucketNode * pb = new bucketNode;
If (NULL = pb)
Return false;
Pb-> data = data;
If (NULL = bucket | pb-> data <bucket-> data)
{// Insert before the first element
Pb-> next = bucket;
Bucket = pb;
Return true;
}
 
BucketNode * ptemp = bucket;
BucketNode * ptempn = bucket-> next;
While (ptempn)
{// Insert after the first element (that is in the middle)
If (pb-> data <ptempn-> data)
{
Pb-> next = ptempn;
Ptemp-> next = pb;
Break;
}
Ptemp = ptempn;
Ptempn = ptempn-> next;
}
If (NULL = ptempn)
{// Insert after the last element
Ptemp-> next = pb;
Pb-> next = NULL;
}
 
Return true;
}
 
Void destroyBucketList (bucketList bucketArr [])
{
For (int I = 0; I <N; I ++)
{
While (bucketArr [I]! = NULL)
{
BucketNode * pb = bucketArr [I];
BucketArr [I] = bucketArr [I]-> next;
Delete pb;
Pb = NULL;
}
}

}
Void bucketSort (double input [], bucketList bucketArr [], int n)
{
For (int I = 1; I <= n; I ++)
{
Int index = (int) floor (input [I] * n );
InsertBucketWithSorting (bucketArr [index], input [I]);
}
 
}
 
Int main ()
{
InitBucketList (bucketArr );
BucketSort (input, bucketArr, N );
Print (bucketArr );
 
DestroyBucketList (bucketArr );
 
Return 0;
}

# Include <stdio. h>
# Include <math. h>

Const int N = 10;
Double input [N + 1] = {-1, 0.78, 0.17, 0.39, 0.26, 0.72, 0.94, 0.21 };
Typedef struct BucketNode
{
Double data;
Struct BucketNode * next;
} * BucketList, bucketNode;
BucketList bucketArr [N];

Void print (bucketList bucketArr [])
{
For (int I = 0; I <N; I ++)
{
BucketNode * pb = bucketArr [I];
While (pb)
{
Printf ("% e", pb-> data );
Pb = pb-> next;
}
Printf ("\ n ");

}
Printf ("\ n ");
}

Void initBucketList (bucketList bucketArr [])
{
For (int I = 0; I <N; I ++)
{
BucketArr [I] = NULL;
}
}
Bool insertBucketWithSorting (bucketList & bucket, double data)
{// Sorting while inserting
BucketNode * pb = new bucketNode;
If (NULL = pb)
Return false;
Pb-> data = data;
If (NULL = bucket | pb-> data <bucket-> data)
{// Insert before the first element
Pb-> next = bucket;
Bucket = pb;
Return true;
}

BucketNode * ptemp = bucket;
BucketNode * ptempn = bucket-> next;
While (ptempn)
{// Insert after the first element (that is in the middle)
If (pb-> data <ptempn-> data)
{
Pb-> next = ptempn;
Ptemp-> next = pb;
Break;
}
Ptemp = ptempn;
Ptempn = ptempn-> next;
}
If (NULL = ptempn)
{// Insert after the last element
Ptemp-> next = pb;
Pb-> next = NULL;
}

Return true;
}

Void destroyBucketList (bucketList bucketArr [])
{
For (int I = 0; I <N; I ++)
{
While (bucketArr [I]! = NULL)
{
BucketNode * pb = bucketArr [I];
BucketArr [I] = bucketArr [I]-> next;
Delete pb;
Pb = NULL;
}
}
 
}
Void bucketSort (double input [], bucketList bucketArr [], int n)
{
For (int I = 1; I <= n; I ++)
{
Int index = (int) floor (input [I] * n );
InsertBucketWithSorting (bucketArr [index], input [I]);
}

}

Int main ()
{
InitBucketList (bucketArr );
BucketSort (input, bucketArr, N );
Print (bucketArr );

DestroyBucketList (bucketArr );

Return 0;
}


 

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.