【C语言/数据结构】排序(归并排序|计数排序|排序算法复杂度)

简介: 【C语言/数据结构】排序(归并排序|计数排序|排序算法复杂度)

归并排序

归并过程如下:




 代码实现(递归)


//时间复杂度:O(N*logN)
//空间复杂度:O(N)
void _MergeSort(int* a,int begin, int end,int* tmp)
{
  if (begin >= end)
  return;
  int mid = (begin + end) / 2;
  //[begin,mid][mid+1,end]
  _MergeSort(a, begin, mid, tmp);
  _MergeSort(a, mid+1, end, tmp);
  //[begin,mid][mid+1,end]归并
  int begin1 = begin, end1 = mid;
  int begin2 = mid+1, end2 = end;
  int i = begin;
  while (begin1 <= end1 && begin2 <= end2)
  {
  if (a[begin1] <= a[begin2])
  {
    tmp[i++] = a[begin1++];
  }
  else
  {
    tmp[i++] = a[begin2++];
  }
  }
  while (begin1 <= end1)
  {
  tmp[i++] = a[begin1++];
  }
  while (begin2 <= end2)
  {
  tmp[i++] = a[begin2++];
  }
  memcpy(a + begin, tmp + begin, sizeof(int) * (end - begin + 1));
}
void MergeSort(int* a, int n)
{
  int* tmp = (int*)malloc(sizeof(int) * n);
  if (tmp == NULL)
  {
  perror("malloc fail");
  return;
  }
  _MergeSort(a, 0, n - 1, tmp);
  free(tmp);
}


分析:因为是使用递归实现,开始时需要创建一个新的数组,且递归需要一个区间,因此我们要另外定义一个函数来实现递归。递归的过程跟二叉树的后序遍历类似,应当注意递归的取值范围和结束条件。归并时,我们把左右两个区间的数从头开始比较,小的就放到tmp数组中。第一个while循环的结束条件是直到某一边的数全部放到tmp就结束。然后就把另一个区间的数,全部依次放入tmp数组中,最后再把tmp的数复制给原数组。


代码实现(非递归)

void MergeSortNonR(int* a, int n)
{
  int* tmp = (int*)malloc(sizeof(int) * n);
  if (tmp == NULL)
  {
  perror("malloc fail");
  return;
  }
  int gap = 1;
  while (gap < n)
  {
  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;
    //[begin1,end1][begin2,end2]归并
    if (end1 >= n || begin2 >= n)
    {
    break;
    }
    if (end2 >= n)
    {
    end2 = n - 1;
    }
    int j = begin1;
    while (begin1 <= end1 && begin2 <= end2)
    {
    if (a[begin1] <= a[begin2])
    {
      tmp[j++] = a[begin1++];
    }
    else
    {
      tmp[j++] = a[begin2++];
    }
    }
    while (begin1 <= end1)
    {
    tmp[j++] = a[begin1++];
    }
    while (begin2 <= end2)
    {
    tmp[j++] = a[begin2++];
    }
    memcpy(a + i, tmp + i, sizeof(int) * (end2 - i + 1));
  }
  gap *= 2;
  }
  free(tmp);
}


分析:gap表示每组数的个数。非递归的实现是,开始每组一个数,两两合一,后面比较的过程和递归一样。不过需要注意越界的问题,当end1或者begin2>=n时,就已经越界,这时候就结束循环。当只是end2>=n时,前面数据没有越界,只需要把end2改成n-1即可。一趟归并结束后,gap变为2倍,进行后面的归并,直到gap>=n就停止。


计数排序(非比较排序)

代码实现

void CountSort(int* a, int n)
{
  int min = a[0], max = a[0];
  for (int i = 1; i < n; i++)
  {
  if (a[i] < min)
    min = a[i];
  if (a[i] > max)
    max = a[i];
  }
  int range = max - min + 1;
  int* count = (int*)calloc(range, sizeof(int));
  if (count == NULL)
  {
  perror("calloc fail");
  return;
  }
  //统计次数
  for (int i = 0; i < n; i++)
  {
  count[a[i] - min]++;
  }
  //排序
  int i = 0;
  for (int j = 0; j < range; j++)
  {
  while (count[j]--)
  {
    a[i++] = j + min;
  }
  }
}


分析:计数排序主要有两步:


1.统计相同元素出现的次数

2.根据统计的结果将序列回收到原来的序列中

计数排序需要我们新创建一个统计数组,按理来说,数组下标就可以用来当作统计的数,该位置就来存放该数出现的次数。但是,如果要排序的数是从一千多开始的,这样前面的空间就全部浪费了。所以我们采用相对映射的方法。即用待排序的数中,最大的数-最小的数+1就可以得到范围,从而减少空间浪费。接着用原数组的数减去最小值,将该值作为count数组的下标,即相对映射。最后进行排序,记得加回最小值min,这样数据才不会被改变。


排序算法的复杂度及稳定性

稳定性:指的是相同的数,在排序之后的相对位置没有改变。


分析:


                    时间                                    空间                                              


直接插入:明显的等差数列             无新空间开辟

希尔:前面文章已分析                          无  

选择:参考动图                                     无

堆排序:前面文章已分析                       无

冒泡:等差数列                                      无

快排:二分的思维                             看递归深度

归并:二分的思维                          开辟新的数组

稳定性通过假设来确定,只要有特例是不稳定的,那就是不稳定的。


目录
相关文章
|
28天前
|
机器学习/深度学习 算法 数据挖掘
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构
K-means聚类算法是机器学习中常用的一种聚类方法,通过将数据集划分为K个簇来简化数据结构。本文介绍了K-means算法的基本原理,包括初始化、数据点分配与簇中心更新等步骤,以及如何在Python中实现该算法,最后讨论了其优缺点及应用场景。
95 4
|
2天前
|
存储 运维 监控
探索局域网电脑监控软件:Python算法与数据结构的巧妙结合
在数字化时代,局域网电脑监控软件成为企业管理和IT运维的重要工具,确保数据安全和网络稳定。本文探讨其背后的关键技术——Python中的算法与数据结构,如字典用于高效存储设备信息,以及数据收集、异常检测和聚合算法提升监控效率。通过Python代码示例,展示了如何实现基本监控功能,帮助读者理解其工作原理并激发技术兴趣。
41 20
|
26天前
|
数据采集 存储 算法
Python 中的数据结构和算法优化策略
Python中的数据结构和算法如何进行优化?
|
1月前
|
算法
数据结构之路由表查找算法(深度优先搜索和宽度优先搜索)
在网络通信中,路由表用于指导数据包的传输路径。本文介绍了两种常用的路由表查找算法——深度优先算法(DFS)和宽度优先算法(BFS)。DFS使用栈实现,适合路径问题;BFS使用队列,保证找到最短路径。两者均能有效查找路由信息,但适用场景不同,需根据具体需求选择。文中还提供了这两种算法的核心代码及测试结果,验证了算法的有效性。
99 23
|
25天前
|
并行计算 算法 测试技术
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面
C语言因高效灵活被广泛应用于软件开发。本文探讨了优化C语言程序性能的策略,涵盖算法优化、代码结构优化、内存管理优化、编译器优化、数据结构优化、并行计算优化及性能测试与分析七个方面,旨在通过综合策略提升程序性能,满足实际需求。
56 1
|
1月前
|
存储 人工智能 算法
数据结构实验之C 语言的函数数组指针结构体知识
本实验旨在复习C语言中的函数、数组、指针、结构体与共用体等核心概念,并通过具体编程任务加深理解。任务包括输出100以内所有素数、逆序排列一维数组、查找二维数组中的鞍点、利用指针输出二维数组元素,以及使用结构体和共用体处理教师与学生信息。每个任务不仅强化了基本语法的应用,还涉及到了算法逻辑的设计与优化。实验结果显示,学生能够有效掌握并运用这些知识完成指定任务。
55 4
|
1月前
|
C语言
【数据结构】二叉树(c语言)(附源码)
本文介绍了如何使用链式结构实现二叉树的基本功能,包括前序、中序、后序和层序遍历,统计节点个数和树的高度,查找节点,判断是否为完全二叉树,以及销毁二叉树。通过手动创建一棵二叉树,详细讲解了每个功能的实现方法和代码示例,帮助读者深入理解递归和数据结构的应用。
132 8
|
1月前
|
算法 vr&ar 计算机视觉
数据结构之洪水填充算法(DFS)
洪水填充算法是一种基于深度优先搜索(DFS)的图像处理技术,主要用于区域填充和图像分割。通过递归或栈的方式探索图像中的连通区域并进行颜色替换。本文介绍了算法的基本原理、数据结构设计(如链表和栈)、核心代码实现及应用实例,展示了算法在图像编辑等领域的高效性和灵活性。同时,文中也讨论了算法的优缺点,如实现简单但可能存在堆栈溢出的风险等。
43 0
|
23天前
|
存储 C语言 开发者
【C语言】字符串操作函数详解
这些字符串操作函数在C语言中提供了强大的功能,帮助开发者有效地处理字符串数据。通过对每个函数的详细讲解、示例代码和表格说明,可以更好地理解如何使用这些函数进行各种字符串操作。如果在实际编程中遇到特定的字符串处理需求,可以参考这些函数和示例,灵活运用。
46 10
|
23天前
|
存储 程序员 C语言
【C语言】文件操作函数详解
C语言提供了一组标准库函数来处理文件操作,这些函数定义在 `<stdio.h>` 头文件中。文件操作包括文件的打开、读写、关闭以及文件属性的查询等。以下是常用文件操作函数的详细讲解,包括函数原型、参数说明、返回值说明、示例代码和表格汇总。
43 9