【数据结构】排序算法——Lesson2

简介: 【7月更文挑战第24天】

前言
本文将继续介绍两种高效的排序算法——归并排序、计算排序。
归并排序在一些场合下(如外部排序)非常有效,当数据量非常大且无法全部加载到内存时,可以将其分块处理。
而计数排序是一种非比较排序算法,适用于特定范围内的整数排序,在许多数情况下计算排序可以秒杀我们介绍过的所有排序。

一、排序算法
1、归并排序
| 算法思路:

归并排序是建立在归并操作上的一种有效的排序算法,该算法是采用分治法的一个非常典型的应用,将已有序的子序列合并,得到完全有序的序列,即先使每个子序列有序,再使子序列间段有序。

动图演示:

代码实现:

//子函数
void _MergeSort(int arr, int tmp, int begin, int end)
{
if (begin == end)
{
return;
}
int mid = (begin + end) / 2;
//[begin, mid] [mid + 1, end]
_MergeSort(arr, tmp, begin, mid);
_MergeSort(arr, tmp, mid + 1, end);

int begin1 = begin, end1 = mid;
int begin2 = mid + 1, end2 = end;
int i = begin;
while (begin1 <= end1 && begin2 <= end2)
{
    if (arr[begin1] < arr[begin2])
    {
        tmp[i++] = arr[begin1++];
    }
    else
    {
        tmp[i++] = arr[begin2++];
    }
}
while (begin1 <= end1)
{
    tmp[i++] = arr[begin1++];
}
while (begin2 <= end2)
{
    tmp[i++] = arr[begin2++];
}
memcpy(arr + begin, tmp + begin, (end - begin + 1) * sizeof(int));

}

//归并排序
void MergeSort(int arr, int n)
{
int
tmp = (int)malloc(n sizeof(int));
if (tmp == NULL)
{
perror("malloc fail");
return;
}
_MergeSort(arr, tmp, 0, n - 1);

free(tmp);
tmp = NULL;

}
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
归并排序有几个需要特别注意的点:

分割区间一定要按[begin, mid] [mid + 1, end]分,不然会导致死循环
memcpy(arr + begin, tmp + begin, (end - begin + 1) sizeof(int));
一定是归并一组拷贝一组,因为如果存在越界的情况还整体拷贝肯定会出错
归并排序算法的时间复杂度是:O(N
logN),空间复杂度是:O(N).
2、归并非递归
递归改非递归有两种办法,一种是用栈模拟,一种是用循环处理。

上篇文章中快排非递归我们是利用栈实现的,但是归并的非递归使用栈解决不了,因为快排的递归过程是一个类似前序遍历的过程,而归并是一个类似后续的过程,它是先将区间循环分割成只有一个数据,再反向进行归并,栈是做不到这一点的。
所以归并的非递归我们考虑用循环来实现。

我们可以直接将原数组一一归并,再二二归并,再四四归并……

//归并非递归
void MergeSortNonR(int arr, int n)
{
int
tmp = (int)malloc(n sizeof(int));
if (tmp == NULL)
{
perror("malloc fail");
return;
}

//gap是每组归并数据的个数
int gap = 1;
while (gap < n)
{
    //i表示每组归并的起始位置
    for (int i = 0; i < n; i += 2 * gap)
    {
        int begin1 = i, end1 = i + gap - 1;
        int begin2 = i + gap, end2 = i + 2 * gap - 1;

        int j = i;
        while (begin1 <= end1 && begin2 <= end2)
        {
            if (arr[begin1] < arr[begin2])
            {
                tmp[j++] = arr[begin1++];
            }
            else
            {
                tmp[j++] = arr[begin2++];
            }
        }
        while (begin1 <= end1)
        {
            tmp[j++] = arr[begin1++];
        }
        while (begin2 <= end2)
        {
            tmp[j++] = arr[begin2++];
        }
        //
        memcpy(arr + i, tmp + i, (end2 - i + 1) * sizeof(int));
    }
    gap *= 2;//一一归,二二归,四四归
}

free(tmp);
tmp = NULL;

}

相关文章
|
7月前
|
算法 数据处理 C语言
C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合
本文深入解析了C语言中的位运算技巧,涵盖基本概念、应用场景、实用技巧及示例代码,并讨论了位运算的性能优势及其与其他数据结构和算法的结合,旨在帮助读者掌握这一高效的数据处理方法。
235 1
|
8月前
|
存储 人工智能 算法
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
这篇文章详细介绍了Dijkstra和Floyd算法,这两种算法分别用于解决单源和多源最短路径问题,并且提供了Java语言的实现代码。
260 3
数据结构与算法细节篇之最短路径问题:Dijkstra和Floyd算法详细描述,java语言实现。
|
4月前
|
存储 机器学习/深度学习 算法
C 408—《数据结构》算法题基础篇—链表(下)
408考研——《数据结构》算法题基础篇之链表(下)。
129 29
|
4月前
|
存储 算法 C语言
C 408—《数据结构》算法题基础篇—链表(上)
408考研——《数据结构》算法题基础篇之链表(上)。
179 25
|
4月前
|
存储 人工智能 算法
C 408—《数据结构》算法题基础篇—数组(通俗易懂)
408考研——《数据结构》算法题基础篇之数组。(408算法题的入门)
169 23
|
5月前
|
存储 算法 测试技术
【C++数据结构——树】二叉树的遍历算法(头歌教学实验平台习题) 【合集】
本任务旨在实现二叉树的遍历,包括先序、中序、后序和层次遍历。首先介绍了二叉树的基本概念与结构定义,并通过C++代码示例展示了如何定义二叉树节点及构建二叉树。接着详细讲解了四种遍历方法的递归实现逻辑,以及层次遍历中队列的应用。最后提供了测试用例和预期输出,确保代码正确性。通过这些内容,帮助读者理解并掌握二叉树遍历的核心思想与实现技巧。
189 2
|
7月前
|
存储 算法 搜索推荐
Python 中数据结构和算法的关系
数据结构是算法的载体,算法是对数据结构的操作和运用。它们共同构成了计算机程序的核心,对于提高程序的质量和性能具有至关重要的作用
154 33
|
7月前
|
数据采集 存储 算法
Python 中的数据结构和算法优化策略
Python中的数据结构和算法如何进行优化?
152 19
|
7月前
|
算法
数据结构之路由表查找算法(深度优先搜索和宽度优先搜索)
在网络通信中,路由表用于指导数据包的传输路径。本文介绍了两种常用的路由表查找算法——深度优先算法(DFS)和宽度优先算法(BFS)。DFS使用栈实现,适合路径问题;BFS使用队列,保证找到最短路径。两者均能有效查找路由信息,但适用场景不同,需根据具体需求选择。文中还提供了这两种算法的核心代码及测试结果,验证了算法的有效性。
278 23
|
7月前
|
算法
数据结构之蜜蜂算法
蜜蜂算法是一种受蜜蜂觅食行为启发的优化算法,通过模拟蜜蜂的群体智能来解决优化问题。本文介绍了蜜蜂算法的基本原理、数据结构设计、核心代码实现及算法优缺点。算法通过迭代更新蜜蜂位置,逐步优化适应度,最终找到问题的最优解。代码实现了单链表结构,用于管理蜜蜂节点,并通过适应度计算、节点移动等操作实现算法的核心功能。蜜蜂算法具有全局寻优能力强、参数设置简单等优点,但也存在对初始化参数敏感、计算复杂度高等缺点。
185 20