排序

一.归并排序

 1 #include<iostream>
 2 using namespace std;
 3 
 4 template<typename T>
 5 void Merge(T A[], int p, int q, int r)
 6 {
 7     int n1 = q - p + 1;
 8     int n2 = r - q;
 9 
10     T *B = new T[n1];
11     T *C = new T[n2];
12 
13     for (int i = p; i <= q; i++)
14     {
15         B[i - p] = A[i];
16     }
17     for (int i = q + 1; i <= r; i++)
18     {
19         C[i - q - 1] = A[i];
20     }
21 
22     int m = 0, n = 0;
23     for (int i = p; i <= r; i++)
24     {
25         if (m == n1 && n != n2)
26         {
27             while (n != n2)
28             {
29                 A[i] = C[n];
30                 i++;
31                 n++;
32             }
33             break;
34         }
35         if (m != n1 && n == n2)
36         {
37             while (m != n1)
38             {
39                 A[i] = B[m];
40                 i++;
41                 m++;
42             }
43             break;
44         }
45         if (B[m] <= C[n])
46         {
47             A[i] = B[m];
48             m++;
49         }
50         else
51         {
52             A[i] = C[n];
53             n++;
54         }
55     }
56 }
57 
58 template<typename T>
59 void MergeSort(T A[], int p, int r)
60 {
61     if (A != NULL && p >= 0 && r >= 0 && p < r)
62     {
63         int q = (p + r) / 2;
64         MergeSort(A, p, q);
65         MergeSort(A, q + 1, r);
66         Merge(A, p, q, r);
67     }
68 }
69 
70 int main()
71 {
72     double A[] = { 1.1, -2.1, 3, 3, 4, -10, 4, 2.6 };
73     MergeSort(A, 0, 7);
74     for (int i = 0; i < 8; i++)
75     {
76         cout << A[i] << " ";
77     }
78     cout << endl;
79     return 0;
80 }

归并排序最大的特色就是它是一种稳定的排序算法。归并过程中是不会改变元素的相对位置的。 缺点是,它需要O(n)的额外空间。但是很适合于多链表排序。

适用于排序大列表,基于分治法。

二.插入排序

 1 #include<iostream>
 2 using namespace std;
 3 
 4 template <typename T>
 5 void InsertionSort(T A[], int length)
 6 {
 7     if (A == NULL || length <= 0)
 8         return;
 9     for (int i = 1; i < length; i++)
10     {
11         T num = A[i];
12         int j = i - 1;
13         while (j >= 0 && num < A[j])
14         {
15             A[j + 1] = A[j];
16             j--;
17         }
18         A[j + 1] = num;
19     }
20 }
21 
22 int main()
23 {
24     double A[] = { 1.1, -2.1, 3, 3, 4, -10, 4, 2.6 };
25     InsertionSort(A, 8);
26     for (int i = 0; i < 8; i++)
27     {
28         cout << A[i] << " ";
29     }
30     cout << endl;
31     return 0;
32 }

稳定性,就是有两个相同的元素,排序先后的相对位置是否变化,主要用在排序时有多个排序规则的情况下。在插入排序中,K1是已排序部分中的元素,当K2和K1比较时,直接插到K1的后面(没有必要插到K1的前面,这样做还需要移动,因此,插入排序是稳定的。

适用于排序小列表若列表基本有序,则插入排序比冒泡、选择更有效率。

三.快速排序

 1 #include<iostream>
 2 using namespace std;
 3 
 4 template <typename T>
 5 int Partition(T A[], int p, int r)
 6 {
 7     T x = A[r];
 8     int i = p - 1;
 9     for (int j = p; j <= r - 1; j++)
10     {
11         if (A[j] <= x)
12         {
13             i++;
14             T temp = A[j];
15             A[j] = A[i];
16             A[i] = temp;
17         }
18     }
19     T temp = A[i + 1];
20     A[i + 1] = A[r];
21     A[r] = temp;
22     return i + 1;
23 }
24 
25 template <typename T>
26 void QuickSort(T A[], int p, int r)
27 {
28     if (A != NULL && p >= 0 && r >= 0 && p < r)
29     {
30         int q = Partition(A, p, r);
31         QuickSort(A, p, q - 1);
32         QuickSort(A, q + 1, r);
33     }
34 }
35 
36 int main()
37 {
38     double A[] = { 1.1, -2.1, 3, 3, 4, -10, 4, 2.6 };
39     QuickSort(A, 0, 7);
40     for (int i = 0; i < 8; i++)
41     {
42         cout << A[i] << " ";
43     }
44     cout << endl;
45     return 0;
46 }

由于每次都需要和中轴元素交换,因此原来的顺序就可能被打乱。如序列为 5 3 3 4 9 8 9 10 6 会将9的顺序打乱。所以说,快速排序是不稳定的!

平均效率O(nlogn),适用于排序大列表。 
此算法的总时间取决于枢纽值的位置;选择第一个元素作为枢纽,可能导致O(n²)的最糟用例效率。若数基本有序,效率反而最差。选项中间值作为枢纽,效率是O(nlogn)。 
基于分治法。

若要快排稳定,开额外O(n)空间.每轮partition都直接扫一遍p~r, 小于key的放一个数组,大于key的放另外一个数组. 然后再合并到原数组当中.这样就是稳定的了

快排改进:

 1 #include<iostream>
 2 #include<stdlib.h>
 3 using namespace std;
 4 
 5 template <typename T>
 6 void InsertionSort(T A[], int p, int r)
 7 {
 8     for (int i = p + 1; i <= r; i++)
 9     {
10         T key = A[i];
11         int j = i - 1;
12         while (j >= p && A[j] > key)
13         {
14             A[j + 1] = A[j];
15             j--;
16         }
17         A[j + 1] = key;
18     }
19 }
20 
21 template <typename T>
22 int Partition(T A[], int p, int r)
23 {
24     T x = A[r];
25     int i = p - 1;
26     for (int j = p; j <= r - 1; j++)
27     {
28         if (A[j] <= x)
29         {
30             i++;
31             T temp = A[j];
32             A[j] = A[i];
33             A[i] = temp;
34         }
35     }
36     T temp = A[i + 1];
37     A[i + 1] = A[r];
38     A[r] = temp;
39     return i + 1;
40 }
41 
42 template <typename T>
43 int RandomizedPartition(T A[], int p, int r)
44 {
45     int i = rand() % (r - p + 1) + p;
46     T temp = A[r];
47     A[r] = A[i];
48     A[i] = temp;
49     return Partition(A, p, r);
50 }
51 
52 template <typename T>
53 void QuickSort(T A[], int p, int r)
54 {
55     if (A != NULL && p >= 0 && r >= 0)
56     {
57         if (r - p < 5)
58         {
59             InsertionSort(A, p, r);
60         }
61         else
62         {
63             int q = RandomizedPartition(A, p, r);
64             QuickSort(A, p, q - 1);
65             QuickSort(A, q + 1, r);
66         }
67     }
68 }
69 
70 int main()
71 {
72     double A[] = { 1.1, -2.1, 3, 3, 4, -10, 4, 2.6 ,20, 10};
73     QuickSort(A, 0, 9);
74     for (int i = 0; i < 10; i++)
75     {
76         cout << A[i] << " ";
77     }
78     cout << endl;
79     return 0;
80 }

四.选择排序

 1 #include<iostream>
 2 #include<stdlib.h>
 3 using namespace std;
 4 
 5 template <typename T>
 6 void SelectionSort(T A[], int length)
 7 {
 8     if (A != NULL && length > 0)
 9     {
10         for (int i = 0; i < length - 1; i++)
11         {
12             int smallest = i;
13             for (int j = i + 1; j < length; j++)
14             {
15                 if (A[j] < A[smallest])
16                 {
17                     smallest = j;
18                 }
19             }
20             T temp = A[i];
21             A[i] = A[smallest];
22             A[smallest] = temp;
23         }
24     }
25 }
26 
27 int main()
28 {
29     double A[] = { 1.1, -2.1, 3, 3, 4, -10, 4, 2.6 ,20, 10};
30     SelectionSort(A, 10);
31     for (int i = 0; i < 10; i++)
32     {
33         cout << A[i] << " ";
34     }
35     cout << endl;
36     return 0;
37 }

由于每次都是选取未排序序列A中的最小元素x与A中的第一个元素交换,因此跨距离了,很可能破坏了元素间的相对位置,因此选择排序是不稳定的!比如:3  3  2

效率O(n²),适用于排序小的列表

五.冒泡排序

 1 #include<iostream>
 2 #include<stdlib.h>
 3 using namespace std;
 4 
 5 template <typename T>
 6 void BubbleSort(T A[], int length)
 7 {
 8     if (A != NULL && length > 0)
 9     {
10         for (int i = length - 1; i > 0; i--)
11         {
12             for (int j = 0; j < i; j++)
13             {
14                 if (A[j] > A[j + 1])
15                 {
16                     T temp = A[j + 1];
17                     A[j + 1] = A[j];
18                     A[j] = temp;
19                 }
20             }
21         }
22     }
23 }
24 
25 int main()
26 {
27     double A[] = { 1.1, -2.1, 3, 3, 4, -10, 4, 2.6 ,20, 10};
28     BubbleSort(A, 10);
29     for (int i = 0; i < 10; i++)
30     {
31         cout << A[i] << " ";
32     }
33     cout << endl;
34     return 0;
35 }

排序过程中只交换相邻两个元素的位置。因此,当两个数相等时,是没必要交换两个数的位置的。所以,它们的相对位置并没有改变,冒泡排序算法是稳定的!

效率 O(n²),适用于排序小列表

六.堆排序

 1 #include<iostream>
 2 #include<stdlib.h>
 3 using namespace std;
 4 
 5 int Parent(int i)
 6 {
 7     return i / 2;
 8 }
 9 
10 int Left(int i)
11 {
12     return 2 * i;
13 }
14 
15 int Right(int i)
16 {
17     return 2 * i + 1;
18 }
19 
20 template <typename T>
21 void MaxHeapify(T A[], int i, int length)
22 {
23     if (i > 0)
24     {
25         int l = Left(i);
26         int r = Right(i);
27         int largest;
28         if (l <= length && A[l - 1] > A[i - 1])
29         {
30             largest = l;
31         }
32         else
33         {
34             largest = i;
35         }
36         if (r <= length && A[r - 1] > A[largest - 1])
37         {
38             largest = r;
39         }
40         if (largest != i)
41         {
42             T temp = A[i - 1];
43             A[i - 1] = A[largest - 1];
44             A[largest - 1] = temp;
45             MaxHeapify(A, largest, length);
46         }
47     }
48 }
49 
50 template <typename T>
51 void BuildMaxHeap(T A[], int length)
52 {
53     for (int i = length / 2; i >= 1; i--)
54     {
55         MaxHeapify(A, i, length);
56     }
57 }
58 
59 template <typename T>
60 void HeapSort(T A[], int length)
61 {
62     if (A != NULL && length > 0)
63     {
64         int heapSize = length;
65         BuildMaxHeap(A, length);
66         for (int i = length; i >= 2; i--)
67         {
68             T temp = A[0];
69             A[0] = A[i - 1];
70             A[i - 1] = temp;
71 
72             heapSize--;
73             MaxHeapify(A, 1, heapSize);
74         }
75     }
76 }
77 
78 int main()
79 {
80     double A[] = { 1.1, -2.1, 3, 3, 4, -10, 4, 2.6 ,20, 10};
81     HeapSort(A, 10);
82     for (int i = 0; i < 10; i++)
83     {
84         cout << A[i] << " ";
85     }
86     cout << endl;
87     return 0;
88 }

堆排序的最坏时间复杂度为O(nlgn)。堆排序的平均性能较接近于最坏性能。由于建初始堆所需的比较次数较多,所以堆排序不适宜于记录数较少的文件。堆排序是就地排序,辅助空间为O(1),它是不稳定的排序方法。 

七.计数排序

 1 #include<iostream>
 2 using namespace std;
 3 
 4 void CountingSort(int A[], int k, int length)
 5 {
 6     if (A == NULL || k < 0 || length <= 0)
 7     {
 8         return;
 9     }
10     int *C = new int[k + 1];
11     int *B = new int[length];
12     for (int i = 0; i <= k; i++)
13     {
14         C[i] = 0;
15     }
16     for (int j = 0; j < length; j++)
17     {
18         C[A[j]]++;
19     }
20     for (int i = 1; i <= k; i++)
21     {
22         C[i] += C[i - 1];
23     }
24     for (int j = length - 1; j >= 0; j--)
25     {
26         B[C[A[j]] - 1] = A[j];
27         C[A[j]]--;
28     }
29     for (int j = 0; j < length; j++)
30     {
31         A[j] = B[j];
32     }
33 }
34 
35 
36 int main()
37 {
38     int A[] = { 11, 2, 3, 3, 4, 10, 0, 6 ,20, 10};
39     CountingSort(A, 20, 10);
40     for (int i = 0; i < 10; i++)
41     {
42         cout << A[i] << " ";
43     }
44     cout << endl;
45     return 0;
46 }

 稳定,适用范围比较局限,非负整数,最大值不是很大的情况,数值分布跨度比较小。

八.基数排序

 1 #include<iostream>
 2 #include<math.h>
 3 using namespace std;
 4 
 5 void CountingSort(int A[], int k, int length, int i)
 6 {
 7     int *C = new int[k];
 8     int *B = new int[length];
 9     for (int i = 0; i < k; i++)
10     {
11         C[i] = 0;
12     }
13     for (int j = 0; j < length; j++)
14     {
15         C[(int)(A[j] / pow(10.0, i - 1)) % 10]++;
16     }
17     for (int i = 1; i < k; i++)
18     {
19         C[i] += C[i - 1];
20     }
21     for (int j = length - 1; j >= 0; j--)
22     {
23         B[C[(int)(A[j] / pow(10.0, i - 1)) % 10] - 1] = A[j];
24         C[(int)(A[j] / pow(10.0, i - 1)) % 10]--;
25     }
26     for (int j = 0; j < length; j++)
27     {
28         A[j] = B[j];
29     }
30 }
31 
32 void RadixSort(int A[], int n, int radix, int length)
33 {
34     if (A == NULL || n <= 0 || radix <= 1 || length <= 0)
35     {
36         return;
37     }
38     for (int i = 1; i <= n; i++)
39     {
40         CountingSort(A, radix, length, i);
41     }
42 }
43 
44 int main()
45 {
46     int A[] = { 111, 2, 37, 3, 4, 100, 0, 600, 20, 10};
47     RadixSort(A, 3, 10, 10);
48     for (int i = 0; i < 10; i++)
49     {
50         cout << A[i] << " ";
51     }
52     cout << endl;
53     return 0;
54 }

基数排序过程中不改变元素的相对位置,因此是稳定的!特别适用于非负整数且length >> n的情况。

原文地址:https://www.cnblogs.com/wanderingzj/p/5269979.html