1、插入排序
1.1 算法步骤
将第一待排序序列第一个元素看做一个有序序列,把第二个元素到最后一个元素当成是未排序序列。
从头到尾依次扫描未排序序列,将扫描到的每个元素插入有序序列的适当位置。(如果待插入的元素与有序序列中的某个元素相等,则将待插入元素插入到相等元素的后面。)
1.2算法实现
clike
//插入排序
void Insert_Sort(int num[], int n)
{
int i, j;
for (i = 1; i < n; i++)
{
int key = num[i];
j = i - 1;
while ((j >= 0) && (key < num[j])) {
num[j + 1] = num[j];
j--;
}
num[j + 1] = key;
}
}
最好O(n) 最差O(n^2)
1.3优化
clike
// 折半插入排序
void Insert_Sort_half(int num[], int n)
{
int i, j;
for (i = 1; i < n; i++)
{
int key = num[i];
int left = 0;
int right = i - 1;
while (left <= right)
{
int mid = left + (right - left) / 2;
if (num[mid] < key)
{
left = mid + 1;
}
else
{
right = mid - 1;
}
}
for (j = i - 1; j >= left; j--)
{
num[j + 1] = num[j];
}
num[left] = key;
}
}
2、希尔排序
2.1算法步骤
希尔排序算法的步骤如下:
选择增量序列:首先选择一个增量序列,通常是将数组长度不断除以 2,直到增量为 1。常见的增量序列包括希尔增量序列、Hibbard 增量序列、Sedgewick 增量序列等。
按增量分组:根据所选的增量,将数组分成多个子序列。每个子序列包含相距为增量的元素。例如,如果增量为 3,则第一个子序列包含数组中下标为 0、3、6、9...的元素,第二个子序列包含数组中下标为 1、4、7、10...的元素,以此类推。
对每个子序列进行插入排序:对每个子序列进行插入排序。即,将每个子序列视为一个独立的数组,使用插入排序算法对其进行排序。
缩小增量:逐步缩小增量,重复步骤 2 和步骤 3,直到增量为 1。
最后一次排序:当增量为 1 时,进行最后一次排序。此时,整个数组被视为一个序列,进行一次插入排序。
2.2算法实现
clike
// 希尔排序
void Shell_Sort(int num[], int n)
{
int gap = n / 2;
while (gap > 0)
{
for (int i = gap; i < n; i++)
{
int temp = num[i];
int j = i;
while (j >= gap && num[j - gap] > temp)
{
num[j] = num[j - gap];
j -= gap;
}
num[j] = temp;
}
gap /= 2;
}
}
3、冒泡排序
3.1算法步骤
冒泡排序算法的步骤如下:
比较相邻元素:从数组的第一个元素开始,依次比较相邻的两个元素,如果第一个元素比第二个元素大(升序排序),则交换它们的位置。
一轮排序完成后,最大(或最小)的元素会被移动到数组末尾:经过一轮比较和交换操作后,数组中最大(或最小)的元素会被移动到数组的末尾位置。
重复以上步骤:重复执行步骤 1 和步骤 2,直到所有元素都按照指定的顺序排列好。
优化:通常情况下,每一轮排序后都会确定一个最大(或最小)的元素的位置,因此在下一轮排序时,可以不考虑已经确定位置的元素。
终止条件:如果在一轮排序中没有发生任何交换操作,即数组已经完全有序,可以提前结束排序。
3.2算法实现
clike
// 冒泡排序
void Bubble_Sort(int num[], int n)
{
for (int i = 1; i < n; i++)
{
for (int j = i; j < n; j++)
{
if (num[j] < num[j - 1])
{
int temp = num[j];
num[j] = num[j - 1];
num[j - 1] = temp;
}
}
}
}
4、选择排序
4.1算法步骤
选择排序是一种简单直观的排序算法,它的步骤如下:
遍历数组: 从数组的第一个元素开始,依次遍历到倒数第二个元素。
找到最小元素: 在当前遍历到的元素及其后面的所有元素中,找到最小的元素。
交换位置: 将找到的最小元素与当前遍历到的元素交换位置。
继续遍历: 继续从下一个位置开始重复以上步骤,直到遍历完整个数组。
4.2算法实现
clike
//选择排序
void Select_Sort(int num[], int n)
{
for (int i = 0; i < n - 1; i++)
{
int min = i;
for (int j = i + 1; j < n; j++)
{
if (num[j] < num[min])
min = j;
}
int temp = num[i];
num[i] = num[min];
num[min] = temp;
}
}
5、归并排序
5.1算法步骤
归并排序是一种经典的分治算法,其步骤如下:
分解: 将原始数组递归地分成两个子数组,直到每个子数组只包含一个元素或者是空数组。
解决: 对每个子数组进行排序,如果子数组只包含一个元素,则认为它已经是有序的。
合并: 合并两个已排序的子数组,产生一个新的有序数组。合并过程中,通过比较两个子数组的首元素,选择较小的元素放入新数组,并且移动对应子数组的指针。
递归地合并: 重复上述步骤,直到所有子数组都被合并成一个整体有序的数组。
5.2算法实现
clike
// 归并排序
void Merge(int num[], int l, int q, int r)
{
int n1 = q - l + 1; // 计算左子数组的长度
int n2 = r - q; // 计算右子数组的长度
int* L = new int[n1];
int* R = new int[n2];
// 将原数组分成左右两个子数组
for (int i = 0; i < n1; i++)
L[i] = num[l + i];
for (int j = 0; j < n2; j++)
R[j] = num[q + 1 + j];
// 合并左右两个子数组到原数组
int i = 0, j = 0, k = l;
while (i < n1 && j < n2)
{
if (L[i] <= R[j])
{
num[k] = L[i];
i++;
}
else
{
num[k] = R[j];
j++;
}
k++;
}
// 将剩余元素拷贝到原数组
while (i < n1)
{
num[k] = L[i];
i++;
k++;
}
while (j < n2)
{
num[k] = R[j];
j++;
k++;
}
// 释放临时数组
delete[] L;
delete[] R;
}
void Merge_Sort(int num[], int l, int r)
{
if (l < r)
{
int q = (l + r) / 2;
Merge_Sort(num, l, q);
Merge_Sort(num, q + 1, r);
Merge(num, l, q, r);
}
}
6、快速排序
6.1算法步骤
快速排序的基本步骤:
选择基准值: 从数组中选择一个元素作为基准值。通常选择第一个元素、最后一个元素或者随机一个元素作为基准值。
分区操作: 将数组中小于基准值的元素移到基准值的左侧,大于基准值的元素移到基准值的右侧。这一步通常使用双指针法实现。
递归排序: 对基准值左右两侧的子数组分别递归地执行上述步骤,直到子数组的大小为 0 或 1,即已经有序。
合并结果: 不需要合并操作,因为在分区操作中,元素已经移动到了正确的位置。
6.2代码实现
clike
//快速排序
void swap(int& a, int& b)
{
int temp = a;
a = b;
b = temp;
}
int partition(int num[], int low, int high)
{
int pivot = num[high];
int i = (low - 1);
for (int j = low; j <= high - 1; j++)
{
if (num[j] <= pivot)
{
i++;
swap(num[i], num[j]);
}
}
swap(num[i + 1], num[high]);
return (i + 1);
}
void quick_Sort(int num[], int low, int high)
{
if (low < high) {
// pi 是划分的索引,arr[pi] 正好在其正确的位置
int pi = partition(num, low, high);
// 分别对划分的两个子数组进行快速排序
quick_Sort(num, low, pi - 1);
quick_Sort(num, pi + 1, high);
}
}
7、计数排序
7.1算法步骤:
算法的步骤如下:
(1)找出待排序的数组中最大和最小的元素
(2)统计数组中每个值为i的元素出现的次数,存入数组C的第i项
(3)对所有的计数累加(从C中的第一个元素开始,每一项和前一项相加)
(4)反向填充目标数组:将每个元素i放在新数组的第C(i)项,每放一个元素就将C(i)减去1
7.2算法实现
clike
//计数排序
void countSort(std::vector<int>& arr)
{
if (arr.empty())return;
//找到数组中的最大值和最小值
int max_element = *std::max_element(arr.begin(), arr.end());
int min_element = *std::min_element(arr.begin(), arr.end());
//计算数组的大小
int count_size = max_element - min_element + 1;
//创建技术数组并初始化为0
std::vector<int>count(count_size, 0);
for (int num : arr)
{
count[num - min_element]++;
}
//根据计数重新构建数组
int index = 0;
for (int i = 0; i < count_size; i++)
{
while (count[i] > 0)
{
arr[index++] = i + min_element;
count[i]--;
}
}
}
8、桶排序
8.1算法实现
clike
//桶排序
void bucketSort(std::vector<int>& arr) {
if (arr.empty()) return;
// 找到数组中的最大值和最小值
int max_element = *std::max_element(arr.begin(), arr.end());
int min_element = *std::min_element(arr.begin(), arr.end());
// 计算桶的数量,可以根据具体情况调整桶的数量
int bucket_count = max_element - min_element + 1;
// 创建桶,并初始化为空
std::vector<std::vector<int>> buckets(bucket_count);
// 将元素放入对应的桶中
for (int num : arr) {
int index = num - min_element;
buckets[index].push_back(num);
}
// 对每个桶中的元素进行排序,这里使用了插入排序
for (auto& bucket : buckets) {
sort(bucket.begin(), bucket.end());
}
// 将桶中的元素按顺序放回原始数组中
int index = 0;
for (auto& bucket : buckets) {
for (int num : bucket) {
arr[index++] = num;
}
}
}