1.插入排序
工作原理是通过构建有序序列,对未排序的数据逐个进行插入操作。具体步骤如下:
- 从第一个元素开始,该元素可以认为已经被排序。
- 取出下一个元素,在已经排序的元素序列中从后向前扫描。
- 如果该元素(已排序)大于新元素,将该元素移到下一位置。
- 重复步骤3,直到找到已排序的元素小于或者等于新元素的位置。
- 将新元素插入到该位置后。
- 重复步骤2~5。
详细操作视频: https://www.bilibili.com/video/BV1TD4y1Q751/?spm_id_from=333.337.search-card.all.click
插入排序的时间复杂度为O(n^2),最好情况: O(n) , 空间复杂度: O(1)
在实际应用中适用于数据量较小的情况。
插入排序代码如下:
void InsertSort(int* a, int n)
{
for (int i = 0; i < n - 1; i++)
{
//一次排序
// [0,end] end+1 end是插入位置
int end = i;
int tem = a[end + 1];
while (end >= 0)
{
if (tem < a[end])
{
a[end + 1] = a[end];
end--;
}
else
break;
}
a[end + 1] = tem;
}
}
2.选择排序
工作原理是每次从未排序的数据中选择最小(或最大)的元素,放到已排序序列的末尾。具体步骤如下:
- 在未排序序列中找到最小(或最大)的元素,存放到排序序列的起始位置。
- 从剩余未排序元素中继续寻找最小(或最大)的元素,放到已排序序列的末尾。
- 重复步骤2,直到所有元素均被排序。
选择排序的 时间复杂度为O(n^2),最好情况: O(n^2) 空间复杂度: O(1)
在实际应用中适用于数据量较小的情况。
选择排序代码如下:
void SelectSort(int* a, int n)
{
int star = 0, end = n - 1;
while (star < end)
{
int min = star, max = star;
for (int i = star + 1; i <= end; i++)
{
if (a[i] < a[min])
{
min = i;
}
if (a[i] > a[max])
{
max = i;
}
}
Swap(&a[star], &a[min]);
if (max == star)
max = min;
Swap(&a[end], &a[max]);
star++;
end--;
}
}
3.堆排序
基于完全二叉树的排序算法,它利用堆的数据结构来进行排序。堆是一种特殊的树形数据结构。
基本思想是首先将待排序的序列构建成一个最大堆(或最小堆),然后将堆顶元素与堆的最后一个元素交换并移出堆,然后对剩余的元素重新进行堆调整操作,重复这个过程直到整个序列有序。
时间复杂度: O(n*logn) 最好情况: O(n*logn) 空间复杂度: O(1)
适用于大数据量的排序。由于堆排序需要进行大量的元素交换和堆调整操作,因此它的性能相对较高。
堆排序代码如下:
//堆排序(不受输入数据的影响,而是由算法本身决定的)
void HeapSort(int* a, int n)
{
for( int i = (n-1-1) / 2 ; i >= 0 ; i--)
{
AdjustDown( a , n ,i );
}
int end = n - 1;
while (end > 0)
{
Swap(&a[0], &a[end]);
AdjustDown(a, end, 0);
end--;
}
}
//向下调整
void AdjustDown(int* a, int size, int parent)
{
int child = parent * 2 + 1;
//找出左右孩子中值较小的一个,和parent比较,进而判断是否交换
while (child < size)
{
if (child + 1 < size && a[child + 1] > a[child])
child++;
if (a[parent] < a[child])
{
Swap(&a[child], &a[parent]);
parent = child;
child = parent * 2 + 1;
}
else
break;
}
}
4.快速排序
基本思想是选择一个基准元素,将序列分为两部分,一部分的元素都小于基准元素,另一部分的元素都大于基准元素,然后对这两部分分别进行快速排序,直到整个序列有序。
具体步骤如下:
- 选择一个基准元素,通常是序列中的第一个元素。
- 将序列中小于基准元素的元素移到基准元素的左边,大于基准元素的元素移到基准元素的右边。
- 对基准元素左右两部分分别进行递归的快速排序。
时间复杂度: O(n^2) 最好情况: O(n*logn) 空间复杂度: O(log n)
适用于大数据量的排序。由于快速排序采用了分治的思想,因此在实际应用中具有较高的性能。
快速排序代码如下:
void QuickSort(int* a, int start, int end)
{
if (start >= end) {
return;
}
if (end - start + 1 <= 10)
InsertSort(a, end - start + 1);
else
{
int mid = GetMid(a, start, end);
Swap(&a[mid], &a[start]);
int left = start, right = end;
int key = start;
while (left < right) {
while (a[right] >= a[key] && left < right)
--right;
while (a[left] <= a[key] && left < right)
++left;
if (left < right)
Swap(&a[left], &a[right]);
}
Swap(&a[key], &a[left]);
key = left;
QuickSort(a, start, key - 1);
QuickSort(a, key + 1, end);
}
}
5.归并排序
基本思想是将待排序序列分为若干个子序列,分别进行排序,然后将已排序的子序列合并成一个有序的序列。
具体步骤如下:
- 将待排序序列不断地二分,直到每个子序列只有一个元素。
- 将相邻的子序列两两合并,合并过程中保持元素有序。
- 重复步骤2,直到所有子序列合并成一个完整的有序序列。
详细操作视频: https://www.bilibili.com/video/BV1hs4y1a7aM/?spm_id_from=333.337.search-card.all.click
时间复杂度: O(n*logn) 最好情况: O(n*logn) 空间复杂度: O(n)
归并排序采用了分治的思想,因此在实际应用中具有较高的性能。同时,归并排序也适用于外部排序,因为它对数据的访问方式是顺序访问,不会产生大量的随机访问,适合处理大规模数据。
快速排序代码如下:
//归并排序
void MergeSort(int* a, int n)
{
int* tem = (int*)malloc(sizeof(int) * n);
if (tem == NULL)
return;
_MergeSort(a, 0, n - 1, tem);
free(tem);
}
void _MergeSort(int* a, int start, int end, int* temp)
{
if (start >= end)
return;
int mid = (start + end) / 2;
//分为区间:
// [start , mid] [mid + 1 ,end]
_MergeSort(a, start, mid, temp);
_MergeSort(a, mid + 1, end, temp);
//归并
int start1 = start, end1 = mid;
int start2 = mid + 1, end2 = end;
int i = start;
while (start1 <= end1 && start2 <= end2)
{
if (a[start1] < a[start2])
temp[i++] = a[start1++];
else
temp[i++] = a[start2++];
}
while (start1 <= end1)
temp[i++] = a[start1++];
while (start2 <= end2)
temp[i++] = a[start2++];
// 将合并后的结果拷贝回原数组
memcpy(a + start, temp + start, sizeof(int) * (end - start + 1));
}
额外补充:
我们将排序分为稳定排序和不稳定排序:
稳定排序:两个元素值相同的元素排序后的先后位置不变
不稳定排序:两个元素值相同的元素排序后的先后位置改变
如下图中的序列中, A 指向的 5 在排序前的位置在 B 指向的 5 位置的前面,而排序后 A指向的5仍然在 B 指向的 5 前面,我们就称这种排序是 稳定排序; 相反 则是不稳定排序。
、
常见的稳定排序有: 插入排序 、 冒泡排序 、归并排序 、 基数排序
相反其他排序就是不稳定排序: 希尔排序 、选择排序 、堆排序 、快速排序
以上就全部内容,感谢各位程序员能够看到最后!!!
希望大家多多支持,点点关注!!!