๐ง๐ปโ๐ป ๆๅบ
่ฎฐๅฝไบ C++ ไธญๅ ็งๆๅบๆนๆณ็ๅฎ็ฐใไฝ็ฌ่ฎฐ็จใ
Characteristics of sorting algorithms:
In-place: a sorting algorithm is in-place if $O(1)$ extra space is needed beyond input.
Stability: a sorting algorithm is stable if numbers with the same value appear in the output array in the same order as they do in the input array.
Procedure ๐๐ง๐ฌ๐๐ซ๐ญ๐ข๐จ๐ง-๐๐จ๐ซ๐ญ1
In: An array $A$ of $n$ integers.
Out: A permutation of that array $A$ that is sorted (monotonic).
for $i := 2$ to $A.length$
โโ$key := A[i]$
โโ// Insert $A[i]$ into the sorted subarray $A[1 : i - 1]$
โโ$j := i - 1$
โโwhile $j > 0$ and $A[j] > key$
โโโโ$A[j + 1] := A[j]$
โโโโ$j := j - 1$
โโ$A[j + 1] := key$
โโreturn $A$
One possible implementation with C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
int main()
{
int arr[100], len;
cin >> len;
for (int t = 0; t < len; t++)
cin >> arr[t];
for (int i = 1; i < len; i++)
{
int key = arr[i]; // ๆ่ฆๆฏ่พ็็ไปๆ็้ๅ็ฌๆฝๅบๆฅ
int j = i - 1;
while (j > 0 && arr[j] > key) // ๅฐๆญค็ไธๅ้ข็็ๆฏ่พๅคงๅฐ
{
arr[j + 1] = arr[j]; // ๆๅ้ข็ๅคง็ไพๆฌกๅพๅๆช๏ผ็ฉบๅบไฝ็ฝฎ
j--;
}
arr[j + 1] = key; // ๆๆญค็ๆๅ
ฅๅ้็ไฝ็ฝฎ
}
for (int t = 0; t < len; t++)
cout << arr[t] << " ";
return 0;
}
Procedure ๐๐๐ซ๐ ๐-๐๐จ๐ซ๐ญ
In: An array $A$ of $n$ integers.
Out: A permutation of that array $A$ that is sorted (monotonic).
MergeSort($A[1โฆn]$):
if $n = 1$
โโ$sol[1โฆn] = [1โฆn]$
else
โโ$solLeft[1โฆ(n/2)] := MergeSort(A[1โฆ(n/2)])$
โโ$solRight[1โฆ(n/2)] := MergeSort(A[(n/2 + 1)โฆn])$
โโ$sol[1โฆn] := Merge(solLeft[1โฆ(n/2)], solRight[1โฆ(n/2)])$
return $sol[1โฆn]$
Merge($A[1โฆn], B[1โฆm]$):
$Aindex := 1, Bindex := 1, Result := [ ]$
// Scan $A$ and $B$ from left to right,
// Append the currently smallest to the result array.
while $Aindex \leq A.length$ and $Bindex \leq B.length$
โโif $A[Aindex] \leq B[Aindex]$
โโโโ$Result.AddLast(A[Aindex])$
โโโโ$Aindex := Aindex + 1$
โโelse
โโโโ$Result.AddLast(B[Bindex])$
โโโโ$Bindex := Bindex + 1$
// Copy the remaining elements of A and B
while $Aindex \leq A.length$
โโ$Result.AddLast(A[Aindex])$
โโ$Aindex := Aindex + 1$
while $Bindex \leq B.length$
โโ$Result.AddLast(B[Bindex])$
โโ$Bindex := Bindex + 1$
return $Result$
One possible implementation with C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
void merge(int a[], int result[], int left, int mid, int right)
{
int i = left, j = mid + 1, k = left;
// ๆๅคงๅฐ้กบๅบไพๆฌกๆทปๅ ๅฐ result ๆฐ็ปไธญ
while (i <= mid && j <= right)
{
if (a[i] <= a[j])
result[k++] = a[i++];
else
result[k++] = a[j++];
}
// ๅค็ๅฉไฝ็ๆฐ
while (i <= mid)
result[k++] = a[i++];
while (j <= right)
result[k++] = a[j++];
for (i = left; i <= right; i++)
a[i] = result[i];
}
void merge_sort(int a[], int result[], int left, int right)
{
if (left < right)
{
int mid = (left + right) / 2;
merge_sort(a, result, left, mid);
merge_sort(a, result, mid + 1, right);
merge(a, result, left, mid, right);
}
}
Procedure ๐๐๐๐ฉ-๐๐จ๐ซ๐ญ
- Keep a copy of the root item
- Remove last item and put it to root
- Maintain heap property
- Return the copy of the root item
One possible implementation with C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <bits/stdc++.h>
using namespace std;
// maintain heap property
void heapify(int arr[], int n, int i)
{
int left = 2 * i + 1;
int right = 2 * i + 2;
int largest = i;
if (left < n && arr[left] > arr[largest])
largest = left;
if (right < n && arr[right] > arr[largest])
largest = right;
if (largest != i)
{
swap(arr[i], arr[largest]);
heapify(arr, n, largest);
}
}
void heapSort(int arr[], int n)
{
// build max heap
for (int i = n / 2 - 1; i >= 0; i--)
heapify(arr, n, i);
// swap the root item with the last item,
// then heapify the remaining items
for (int i = n - 1; i >= 0; i--)
{
swap(arr[0], arr[i]);
heapify(arr, i, 0);
}
}
Procedure ๐๐๐ฅ๐๐๐ญ๐ข๐จ๐ง-๐๐จ๐ซ๐ญ
Basic idea: pick out minimum element from input, then recursively sort remaining elements, and finally concatenate the minimum element with sorted remaining elements.
In: An array $A$ of $n$ integers.
Out: A permutation of that array $A$ that is sorted (monotonic).
SelectionSort($A$):
for $i := 1$ to $A.length$
โโ$minIdx := i$
โโfor $j := i + 1$ to $A.length$
โโโโif $A[j] < A[minIdx]$
โโโโโโ$minIdx := j$
โโโโ$Swap(i, minIdx)$
One possible implementation with C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
void SelectSort(int* arr, int n)
{
// ไฟๅญๅไธๅ่ถๆๅบ็็ฌฌไธไธชๆฐๅๆๅไธไธชๆฐ็ไธๆ
int begin = 0, end = n - 1;
while (begin < end)
{
int maxIndex = begin; // ไฟๅญๆๅคงๅผ็ไธๆ
int minIndex = begin; // ไฟๅญๆๅฐๅผ็ไธๆ
// ๆพๅบๆๅคงๅผๅๆๅฐๅผๅฏนๅบ็ไธๆ
for (int i = begin; i <= end; ++i)
{
if (arr[i] < arr[minIndex])
minIndex = i;
if (arr[i] > arr[maxIndex])
maxIndex = i;
}
// ๆๅฐๅผๆพๅจๅบๅๅผๅคด
swap(&arr[minIndex], &arr[begin]);
// ๅฆๆๆๅคงๅผๅๆฌๅจ begin ไฝ็ฝฎ๏ผๅณ maxIndex == begin๏ผ
// ้ฃไนไธ้ข็ๆไฝไผๅฐๆๅคงๅผๆขๅฐไธๆ ไธบ minIndex ๅค๏ผ
// ๆญคๆถ maxIndex ไธๅๆฏๆๅคงๅผ็ไธๆ ๏ผ่ๆฏๆๅฐๅผ็ใ
// ไธบไบ้ฒๆญขไปฅไธๆ
ๅตๅ็๏ผๆไปฌ้่ฆๆดๆฐไธไธ maxIndexใ
if (begin == maxIndex)
maxIndex = minIndex;
// ๆๅคงๅผๆพๅจๅบๅ็ปๅฐพ
swap(&arr[maxIndex], &arr[end]);
++begin;
--end;
}
}
Procedure ๐๐ก๐๐ฅ๐ฅ-๐๐จ๐ซ๐ญ
One possible implementation with C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <bits/stdc++.h>
using namespace std;
void ShellSort(vector<int> &nums)
{
int size = nums.size();
for (int gap = size / 2; gap > 0; gap /= 2)
{
// ไฝฟ็จๆๅ
ฅๆๅบๅฏนๅฝๅ้ด้่ฟ่กๆๅบ
for (int i = gap; i < size; i++)
{
int key = nums[i];
int j = i;
while (j >= gap && nums[j - gap] > key)
{
nums[j] = nums[j - gap];
j -= gap;
}
nums[j] = key;
}
}
}
Procedure ๐๐ฎ๐๐๐ฅ๐-๐๐จ๐ซ๐ญ
Basic idea: repeatedly step through the array, compare adjacent pairs and swaps them if they are in the wrong order. Thus, larger elements โbubbleโ to the โtopโ.
In: An array $A$ of $n$ integers.
Out: A permutation of that array $A$ that is sorted (monotonic).
BubbleSort($A$):
for $i := A.length$ down to $2$
โโfor $j := 1$ to $i - 1$
โโโโif $A[j] > A[j + 1]$
โโโโโโ$Swap(A[j], A[j + 1])$
One possible implementation with C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
void BubbleSort(int arr[], int len)
{
int i, j;
for (i = 0; i < len - 1; i++)
{
for (j = 0; j < len - 1 - i; j++)
{
if (arr[j] > arr[j + 1])
{
swap(arr[j], arr[j + 1]);
}
}
}
}
Procedure ๐๐ฎ๐ข๐๐ค-๐๐จ๐ซ๐ญ
Basic idea: Given an array $A$ of $n$ items.
- Choose one item $x$ in $A$ as the pivot.
- Use the pivot to partition the input into $B$ and $C$, so that items in $B$ are $\leq x$, and items in $C$ are $> x$.
- Recursively sort $B$ and $C$.
- Output $โจB, x, Cโฉ$.
In: An array $A$ of $n$ integers.
Out: A permutation of that array $A$ that is sorted (monotonic).
QuickSortAbs($A$):
$x := GetPivot(A)$
$<B, C> := Partition(A, x)$
$QuickSortAbs(B)$
$QuickSortAbs(C)$
return $Concatenate(B, x, C)$
One possible implementation with C++:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <bits/stdc++.h>
using namespace std;
// ้ๅฎไธไธช pivot ๅนถๅฐ left ๅฐ right ไน้ด็ๅ
็ด ้่ฟ pivot ๅๅๆไธค้จๅ๏ผ
// ไฝฟๅพ pivot ๅทฆ่พน็ๅ
็ด ้ฝๅฐไบๅฎ๏ผๅณ่พน็ๅ
็ด ้ฝๅคงไบๅฎ๏ผ็ถๅ่ฟๅ pivot ็ไธๆ
int _partition(vector<int> &nums, int left, int right)
{
int pivot = nums[left]; // ไปค pivot ไธบๅทฆ่พน็ฌฌไธไธชๅ
็ด
while (left < right)
{
// ๅฆๆๅณ่พนๅ
็ด ๅคงไบ pivot๏ผไธ็ฎก๏ผๅไน๏ผๅ่ฎฉๅฎๅฐๅทฆ่พนๅป
while (left < right && nums[right] >= pivot)
right--;
nums[left] = nums[right];
// ๅฆๆๅทฆ่พนๅ
็ด ๅฐไบ pivot๏ผไธ็ฎก๏ผๅไน๏ผๅ่ฎฉๅฎๅฐๅณ่พนๅป
while (left < right && nums[left] <= pivot)
left++;
nums[right] = nums[left];
}
nums[left] = pivot; // ๆๅ่ฎฐๅพๆขๅค pivot๏ผ๏ผ๏ผ
return left;
}
// ๅฐ nums ้่ฟ _partition ๅๅๆไธค้จๅ๏ผๅฏนๆฏไธช้จๅ่ฐ็จ _quick_sort
void _quick_sort(vector<int> &nums, int left, int right)
{
if (left < right)
{
int p = _partition(nums, left, right);
_quick_sort(nums, left, p - 1);
_quick_sort(nums, p + 1, right);
}
}
void QuickSort(vector<int> &nums)
{
_quick_sort(nums, 0, nums.size() - 1);
}
Procedure ๐๐ฎ๐๐ค๐๐ญ-๐๐จ๐ซ๐ญ
- Create $d$ empty lists. (These are the buckets.)
- Scan through input, for each item, append it to the end of the corresponding list.
- Concatenate all lists.
This algorithm only takes $\Theta(n)$ time.
- This is not a comparison based algorithm.
- No comparison between items are made.
- Instead the algorithm uses actual values of the items.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
void bucketSort(vector<int> &nums)
{
int n = nums.size();
int mn = nums[0], mx = nums[0];
for (int i = 1; i < n; i++)
{
mn = min(mn, nums[i]);
mx = max(mx, nums[i]);
}
int size = (mx - mn) / n + 1; // size ่ณๅฐ่ฆไธบ1
int cnt = (mx - mn) / size + 1; // ๆกถ็ไธชๆฐ่ณๅฐ่ฆไธบ1
vector<vector<int>> buckets(cnt);
for (int i = 0; i < n; i++)
{
int idx = (nums[i] - mn) / size;
buckets[idx].push_back(nums[i]);
}
for (int i = 0; i < cnt; i++)
{
sort(buckets[i].begin(), buckets[i].end());
}
int index = 0;
for (int i = 0; i < cnt; i++)
{
for (int j = 0; j < buckets[i].size(); j++)
{
nums[index++] = buckets[i][j];
}
}
}
Procedure ๐๐๐๐ข๐ฑ-๐๐จ๐ซ๐ญ
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
int maxbit(int data[], int n) // ่พ
ๅฉๅฝๆฐ๏ผๆฑๆฐๆฎ็ๆๅคงไฝๆฐ
{
int maxData = data[0]; // ๆๅคงๆฐ
// ๅ
ๆฑๅบๆๅคงๆฐ๏ผๅๆฑๅ
ถไฝๆฐ๏ผ่ฟๆ ทๆๅๅ
ไพๆฌกๆฏไธชๆฐๅคๆญๅ
ถไฝๆฐ๏ผ็จๅพฎไผๅ็นใ
for (int i = 1; i < n; ++i)
{
if (maxData < data[i])
maxData = data[i];
}
int d = 1;
int p = 10;
while (maxData >= p)
{
maxData /= 10;
++d;
}
return d;
}
void radixsort(int data[], int n) // ๅบๆฐๆๅบ
{
int d = maxbit(data, n);
int *tmp = new int[n];
int *count = new int[10]; // ่ฎกๆฐๅจ
int i, j, k;
int radix = 1;
for (i = 1; i <= d; i++) // ่ฟ่ก d ๆฌกๆๅบ
{
for (j = 0; j < 10; j++)
count[j] = 0; // ๆฏๆฌกๅ้
ๅๆธ
็ฉบ่ฎกๆฐๅจ
for (j = 0; j < n; j++)
{
k = (data[j] / radix) % 10; // ็ป่ฎกๆฏไธชๆกถไธญ็่ฎฐๅฝๆฐ
count[k]++;
}
for (j = 1; j < 10; j++)
count[j] = count[j - 1] + count[j]; // ๅฐ tmp ไธญ็ไฝ็ฝฎไพๆฌกๅ้
็ปๆฏไธชๆกถ
for (j = n - 1; j >= 0; j--) // ๅฐๆๆๆกถไธญ่ฎฐๅฝไพๆฌกๆถ้ๅฐ tmp ไธญ
{
k = (data[j] / radix) % 10;
tmp[count[k] - 1] = data[j];
count[k]--;
}
for (j = 0; j < n; j++) // ๅฐไธดๆถๆฐ็ป็ๅ
ๅฎนๅคๅถๅฐ data ไธญ
data[j] = tmp[j];
radix = radix * 10;
}
delete[] tmp;
delete[] count;
}
Summary
Algorithms | Best | Worst | Average | In/Out-Place | Stability |
---|---|---|---|---|---|
Insertion-Sort | $O(n^2)$ | $O(n^2)$ | $O(n^2)$ | In-place | True |
Merge-Sort | $O(n\log{n})$ | $O(n\log{n})$ | $O(n\log{n})$ | Out-place | True |
Heap-Sort | $O(n\log{n})$ | $O(n\log{n})$ | $O(n\log{n})$ | In-place | False |
Selection-Sort | $O(n^2)$ | $O(n^2)$ | $O(n^2)$ | In-place | False |
Shell-Sort | $O(n\log{n})$ | $O(n^2)$ | - | In-place | False |
Bubble-Sort | $O(n)$ | $O(n^2)$ | $O(n^2)$ | In-place | True |
Quick-Sort | $O(n\log{n})$ | $O(n\log{n})$ | $O(n\log{n})$ | In-place | False |
Bucket-Sort | $O(n + k)$ | $O(n^2)$ | $O(n + k)$ | Out-place | True |
Radix-Sort | $O(n \cdot k)$ | $O(n \cdot k)$ | $O(n \cdot k)$ | Out-place | True |