-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSortAlgorithm.cpp
More file actions
275 lines (251 loc) · 8.06 KB
/
SortAlgorithm.cpp
File metadata and controls
275 lines (251 loc) · 8.06 KB
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
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
#include<iostream>
using namespace std;
//快速排序
// 分类 ------------ 内部比较排序
// 数据结构 --------- 数组
// 最差时间复杂度 ---- 每次选取的基准都是最大(或最小)的元素,导致每次只划分出了一个分区,需要进行n-1次划分才能结束递归,时间复杂度为O(n^2)
// 最优时间复杂度 ---- 每次选取的基准都是中位数,这样每次都均匀的划分出两个分区,只需要logn次划分就能结束递归,时间复杂度为O(nlogn)
// 平均时间复杂度 ---- O(nlogn)
// 所需辅助空间 ------ 主要是递归造成的栈空间的使用(用来保存left和right等局部变量),取决于递归树的深度,一般为O(logn),最差为O(n)
// 稳定性 ---------- 不稳定
void QuickSort(int arr[], int l, int r)
{
if (l < r)
{
int temp = arr[l];
int i, j, k;
i = l, j = r;
while (i < j)
{
while (i < j&&temp <= arr[j])//先找到右边第一个比temp小的元素,然后将它向左移动
j--;
arr[i++] = arr[j];
while (i < j&&temp >= arr[i])//找到左边第一个比temp大的元素,然后将它向右移
i++;
arr[j--] = arr[i];
}
arr[i] = temp;//中间(指左边的数小于temp,右边的数大于temp)这个空用temp补上
//递归调用
QuickSort(arr, l, i-1);
QuickSort(arr, j+1, r);
}
}
//插入排序
// 分类 ------------- 内部比较排序
// 数据结构 ---------- 数组
// 最差时间复杂度 ---- 最坏情况为输入序列是降序排列的,此时时间复杂度O(n^2)
// 最优时间复杂度 ---- 最好情况为输入序列是升序排列的,此时时间复杂度O(n)
// 平均时间复杂度 ---- O(n^2)
// 所需辅助空间 ------ O(1)
// 稳定性 ------------ 稳定
void InsertSort(int arr[], int n)
{
int i, j;
for (i = 1; i < n; i++)
{
int temp = arr[i];
j = i - 1;
while (j >= 0 && arr[j] > temp)
{
arr[j + 1] = arr[j];
j--;
}
arr[j+1] = temp;
}
}
//冒泡排序
// 分类 -------------- 内部比较排序
// 数据结构 ---------- 数组
// 最差时间复杂度 ---- O(n^2)
// 最优时间复杂度 ---- 如果能在内部循环第一次运行时,使用一个旗标来表示有无需要交换的可能,可以把最优时间复杂度降低到O(n)
// 平均时间复杂度 ---- O(n^2)
// 所需辅助空间 ------ O(1)
// 稳定性 ------------ 稳定
void BubbleSort(int arr[], int n)
{
int i, j, temp;
for(i=0;i<n-1;i++)
for(j=0;j<n-1-i;j++)//每次最大元素往后移动,则比较次数n-1-i
if (arr[j] > arr[j+1])
{
temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
//选择排序
// 分类 -------------- 内部比较排序
// 数据结构 ---------- 数组
// 最差时间复杂度 ---- O(n^2)
// 最优时间复杂度 ---- O(n^2)
// 平均时间复杂度 ---- O(n^2)
// 所需辅助空间 ------ O(1)
// 稳定性 ------------ 不稳定
void SelectSort(int arr[], int n)
{
int i, j,temp;
for (i = 0; i < n - 1; i++) // i为已排序序列的末尾
{
int min = i;
for (j = i + 1; j < n; j++) // 未排序序列,相当于每次从未排序的部分选出最小的添加到排过序的末尾
{
if (arr[j] < arr[min]) // 找出未排序序列中的最小值
{
min = j;
}
}
if (min != i)
{
temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
}
}
}
//希尔排序
// 分类 -------------- 内部比较排序
// 数据结构 ---------- 数组
// 最差时间复杂度 ---- 根据步长序列的不同而不同。已知最好的为O(n(logn)^2)
// 最优时间复杂度 ---- O(n)
// 平均时间复杂度 ---- 根据步长序列的不同而不同。
// 所需辅助空间 ------ O(1)
// 稳定性 ------------ 不稳定
void ShellSort(int arr[], int n)
{
int h = 0;
while (h <= n) // 生成初始增量
{
h = 3 * h + 1;
}
while (h >= 1)
{
for (int i = h; i < n; i++)
{
int j = i - h;
int get = arr[i];
while (j >= 0 && arr[j] > get)
{
arr[j + h] = arr[j];
j = j - h;
}
arr[j + h] = get;
}
h = (h - 1) / 3; // 递减增量
}
}
// 分类 -------------- 内部比较排序
// 数据结构 ---------- 数组
// 最差时间复杂度 ---- O(nlogn)
// 最优时间复杂度 ---- O(nlogn)
// 平均时间复杂度 ---- O(nlogn)
// 所需辅助空间 ------ O(n)
// 稳定性 ------------ 稳定
void Merge(int arr[], int left, int mid, int right)// 合并两个已排好序的数组arr[left...mid]和arr[mid+1...right]
{
int len = right - left + 1;
int *temp = new int[len]; // 辅助空间O(n)
int index = 0;
int i = left; // 前一数组的起始元素
int j = mid + 1; // 后一数组的起始元素
while (i <= mid && j <= right)
{
temp[index++] = arr[i] <= arr[j] ? arr[i++] : arr[j++]; // 带等号保证归并排序的稳定性
}
while (i <= mid)
{
temp[index++] = arr[i++];
}
while (j <= right)
{
temp[index++] = arr[j++];
}
for (int k = 0; k < len; k++)
{
arr[left++] = temp[k];
}
}
void MergeSortRecursion(int arr[], int left, int right) // 递归实现的归并排序(自顶向下)
{
if (left == right) // 当待排序的序列长度为1时,递归开始回溯,进行merge操作
return;
int mid = (left + right) / 2;
MergeSortRecursion(arr, left, mid);
MergeSortRecursion(arr, mid + 1, right);
Merge(arr, left, mid, right);
}
void MergeSortIteration(int arr[], int len) // 非递归(迭代)实现的归并排序(自底向上)
{
int left, mid, right;// 子数组索引,前一个为arr[left...mid],后一个子数组为arr[mid+1...right]
for (int i = 1; i < len; i *= 2) // 子数组的大小i初始为1,每轮翻倍
{
left = 0;
while (left + i < len) // 后一个子数组存在(需要归并)
{
mid = left + i - 1;
right = mid + i < len ? mid + i : len - 1;// 后一个子数组大小可能不够
Merge(arr, left, mid, right);
left = right + 1; // 前一个子数组索引向后移动
}
}
}
//堆排序
// 分类 -------------- 内部比较排序
// 数据结构 ---------- 数组
// 最差时间复杂度 ---- O(nlogn)
// 最优时间复杂度 ---- O(nlogn)
// 平均时间复杂度 ---- O(nlogn)
// 所需辅助空间 ------ O(1)
// 稳定性 ------------ 不稳定
void Swap(int arr[], int i, int j)
{
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
void Heapify(int arr[], int i, int size) // 从arr[i]向下进行堆调整
{
int left_child = 2 * i + 1; // 左孩子索引
int right_child = 2 * i + 2; // 右孩子索引
int max = i; // 选出当前结点与其左右孩子三者之中的最大值
if (left_child < size && arr[left_child] > arr[max])
max = left_child;
if (right_child < size && arr[right_child] > arr[max])
max = right_child;
if (max != i)
{
Swap(arr, i, max); // 把当前结点和它的最大(直接)子节点进行交换
Heapify(arr, max, size); // 递归调用,继续从当前结点向下进行堆调整
}
}
int BuildHeap(int arr[], int n) // 建堆,时间复杂度O(n)
{
int heap_size = n;
for (int i = heap_size / 2 - 1; i >= 0; i--) // 从每一个非叶结点开始向下进行堆调整
Heapify(arr, i, heap_size);
return heap_size;
}
void HeapSort(int arr[], int n)
{
int heap_size = BuildHeap(arr, n); // 建立一个最大堆
while (heap_size > 1)
{ // 堆(无序区)元素个数大于1,未完成排序
// 将堆顶元素与堆的最后一个元素互换,并从堆中去掉最后一个元素
// 此处交换操作很有可能把后面元素的稳定性打乱,所以堆排序是不稳定的排序算法
Swap(arr, 0, --heap_size);
Heapify(arr, 0, heap_size); // 从新的堆顶元素开始向下进行堆调整,时间复杂度O(logn)
}
}
void main()
{
int a[5] = { 16,13,55,1,67 };
//QuickSort(a, 0, size(a) - 1);//减一的原因是要定位到最后一个元素
//InsertSort(a, size(a));
//BubbleSort(a, size(a));
//SelectSort(a, size(a));
//ShellSort(a, size(a));
//MergeSortIteration(a, size(a));
//HeapSort(a, size(a));
for (int i = 0; i < size(a); i++)
cout << a[i]<<" ";
system("pause");
}