算法和数据结构~各位排序算法的介绍与实现(C#)

简介:

上一讲大概介绍了一个排序算法的概念与内存结构图,主要选自《算法精解》,各人认为,这本书写的还是不错的,大家可以直接下载epub版,然后在面度阅读APP上看,挺方便的!其实,学习,很简单!

      排序是指将元素集合按照规定的顺序排列。通常有两种排序方法,升序排列和降序排列。例如,对整数集{5,2,7,1}进行升序排列,结果为{1,2,5,7},对其进行降序排列结果为{7,5,2,1}。总的来说,排序的目的是使数据能够以更有意义的形式表现出来。虽然排序最显著的应用是排列数据以显示它,但它往往可以用来解决其他的问题,特别是作为某些已成型算法的一部分。
      总的来说,排序算法分为两大类:比较排序和线性时间排序。比较排序依赖于比较和交换来将元素移动到正确的位置上。令人惊讶的是,并不是所有的排序算法都依赖于比较。对于那些确实依赖于比较来进行排序的算法来说,它们的运行时间往往不可能小于O(nlg n)。对于线性时间排序,从它的名字就可以看出,它的运行时间往往与它处理的数据元素个数成正比,即为O(n)。遗憾的是,线性时间排序依赖于数据集合中的某些特征,所以我们并不是在所有的场合都能够使用它。某些排序算法只使用数据本身的存储空间来处理和输出数据(这些称为就地排序),而有一些则需要额外的空间来处理和输出数据(虽然可能最终结果还是会拷贝到原始的内存空间中)。

    /// <summary>
    /// 排序算法
    /// 作者:仓储大叔
    /// 代码来源:部分自写,部分网上摘录,都经过测试可以放心使用
    /// </summary>
    public class SortHelper
    {
        #region Public Methods
        /// <summary>
        /// 插入排序
        /// </summary>
        public static void InsertSort(List<int> list)
        {

            /*
             * 复杂度 O(n^2)
             * 插入排序从根本上来说,就是每次从未排序的数据集中取出一个元素,插入已排好序的数据集中。在以下所展示的实现中,两个数据集都存放在data中,data是一块连接的存储区域。最初,data包含size个无序元素。随着issort的运行,data逐渐被有序数据集所取代,直到issort返回(此时,data已经是一个有序数据集)。虽然实现插入排序用到连续的存储空间,但它也能用链表来实现(并不是所有的排序都可以使用链表来实现),并且效率不差。
             */
            for (int j = 1; j < list.Count; j++)
            {
                int i = j - 1;
                int currnet = list[j];
                while (i >= 0 && currnet > list[i])
                {
                    list[i + 1] = list[i];
                    i--;
                }
                list[i + 1] = currnet;
            }
        }
        /// <summary>
        /// 快速排序
        /// </summary>
        /// <param name="list">目标数组</param>
        /// <param name="left">子表的起始位置</param>
        /// <param name="right">子表的终止位置</param>
        public static void QuickSort(List<int> list, int left, int right)
        {
            /*
           * 复杂度 O(nlg^n)
           * 描述 利用快速排序将数组data中的元素进行排序。数组中的元素个数由size决定。而每个元素的大小由esize决定。参数i和k定义当前进行排序的两个部分,其值分别初始化为0和size-1。函数指针compare会指向一个用户定义的函数来比较元素大小。其函数功能与issort中描述的一样。当qksort返回时,data包含已排序的元素
           */
            if (left < right)
            {
                int i = Division(list, left, right);
                //对枢轴的左边部分进行排序
                QuickSort(list, i + 1, right);
                //对枢轴的右边部分进行排序
                QuickSort(list, left, i - 1);
            }
        }
        /// <summary>
        /// 归并排序
        /// </summary>
        /// <param name="array">目标数组</param>
        /// <param name="first">子表的起始位置</param>
        /// <param name="last">子表的终止位置</param>
        public static void MergeSortFunction(List<int> array, int first, int last)
        {
            /*
             * 复杂度 O(nlg^n)
             * 描述 利用归并排序将数组data中的元素进行排序。数组中的元素个数由size决定。而每个元素的大小由esize决定。参数i和k定义当前进行排序的两个部分,其值分别初始化为0和size-1。函数指针compare会指向一个用户定义的函数来比较元素大小。其函数功能与issort中描述的一样。当mgsort返回时,data中包含已排序的元素。
             */
            if (first < last)   //子表的长度大于1,则进入下面的递归处理
            {
                int mid = (first + last) / 2;   //子表划分的位置
                MergeSortFunction(array, first, mid);   //对划分出来的左侧子表进行递归划分
                MergeSortFunction(array, mid + 1, last);    //对划分出来的右侧子表进行递归划分
                MergeSortCore(array, first, mid, last); //对左右子表进行有序的整合(归并排序的核心部分)
            }

        }
        /// <summary>  
        /// 计数排序  
        /// </summary>  
        /// <param name="arrayToSort">要排序的数组</param>  
        /// <param name="maxValue">数组的最大值加一</param>  
        /// <returns>计数排序后的结果</returns>  
        public static List<int> CountingSort(List<int> arrayA, int arrange)
        {
            /* 复杂度 O(n+k),n为要排序的元素的个数,k为data中最大的整数加1。
             * 计数排序是一种高效的线性排序,它通过计算一个集合中元素出现的次数来确定集合如何排列。不同于之前介绍的一些算法是基于比较的,计数排序不需要进行元素比较,而且它的运行效率要比效率为O(nlg n)比较排序高。 
             */

            int[] arrayResult = new int[arrayA.Count];
            int[] arrayTemp = new int[arrange + 1];
            for (int i = 0; i <= arrange; i++)
            {
                arrayTemp[i] = 0;
            }
            for (int j = 0; j < arrayA.Count; j++)
            {
                arrayTemp[arrayA[j]] += 1;
            }
            for (int k = 1; k <= arrange; k++)
            {
                arrayTemp[k] += arrayTemp[k - 1];
            }
            for (int m = arrayA.Count - 1; m >= 0; m--)
            {
                arrayResult[arrayTemp[arrayA[m]] - 1] = arrayA[m];
                arrayTemp[arrayA[m]] -= 1;
            }
            return arrayResult.ToList();
        }
        /// <summary>
        /// 冒泡排序
        /// </summary>
        /// <param name="arr"></param>
        public void EbullitionSort(List<int> arr)
        {
            /*
             * 复杂度O(n^2) 
             * 对1至n个记录,在第i趟排序中设置标志flag:=true,未排序的标志。从下往上扫描,以j作为内层循环变量,共做n-i次比较。在第j趟比较中,若r[j+1]<r[j]则交换,并至flag为false。在一趟排序结束后,若flag为true,则终止排序。
             */
            int i, j, temp;
            bool done = false;
            j = 1;
            while ((j < arr.Count) && (!done))//判断长度    
            {
                done = true;
                for (i = 0; i < arr.Count - j; i++)
                {
                    if (arr[i] > arr[i + 1])
                    {
                        done = false;
                        temp = arr[i];
                        arr[i] = arr[i + 1];//交换数据    
                        arr[i + 1] = temp;
                    }
                }
                j++;
            }
        }

        #endregion

        #region Private Methods
        /// <summary>
        /// 归并排序的核心部分:将两个有序的左右子表(以mid区分),合并成一个有序的表
        /// </summary>
        /// <param name="array"></param>
        /// <param name="first"></param>
        /// <param name="mid"></param>
        /// <param name="last"></param>
        private static void MergeSortCore(List<int> array, int first, int mid, int last)
        {

            int indexA = first; //左侧子表的起始位置
            int indexB = mid + 1;   //右侧子表的起始位置
            int[] temp = new int[last + 1]; //声明数组(暂存左右子表的所有有序数列):长度等于左右子表的长度之和。
            int tempIndex = 0;
            while (indexA <= mid && indexB <= last) //进行左右子表的遍历,如果其中有一个子表遍历完,则跳出循环
            {
                if (array[indexA] <= array[indexB]) //此时左子表的数 <= 右子表的数
                {
                    temp[tempIndex++] = array[indexA++];    //将左子表的数放入暂存数组中,遍历左子表下标++
                }
                else//此时左子表的数 > 右子表的数
                {
                    temp[tempIndex++] = array[indexB++];    //将右子表的数放入暂存数组中,遍历右子表下标++
                }
            }
            //有一侧子表遍历完后,跳出循环,将另外一侧子表剩下的数一次放入暂存数组中(有序)
            while (indexA <= mid)
            {
                temp[tempIndex++] = array[indexA++];
            }
            while (indexB <= last)
            {
                temp[tempIndex++] = array[indexB++];
            }

            //将暂存数组中有序的数列写入目标数组的制定位置,使进行归并的数组段有序
            tempIndex = 0;
            for (int i = first; i <= last; i++)
            {
                array[i] = temp[tempIndex++];
            }

        }

        /// <summary>
        /// 获取按枢轴值左右分流后枢轴的位置
        /// </summary>
        /// <param name="list"></param>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <returns></returns>
        private static int Division(List<int> list, int left, int right)
        {
            while (left < right)
            {
                int num = list[left]; //将首元素作为枢轴
                if (num > list[left + 1])
                {
                    list[left] = list[left + 1];
                    list[left + 1] = num;
                    left++;
                }
                else
                {
                    int temp = list[right];
                    list[right] = list[left + 1];
                    list[left + 1] = temp;
                    right--;
                }
            }
            return left; //指向的此时枢轴的位置
        }
        #endregion

    }

对于算法与数据结构,我们还会继续,有理论,有实现,希望它可以不那么枯燥!

感谢咱们的阅读!

 本文转自博客园张占岭(仓储大叔)的博客,原文链接:算法和数据结构~各位排序算法的介绍与实现(C#),如需转载请自行联系原博主。

目录
相关文章
|
8月前
|
存储 监控 算法
电脑监控管理中的 C# 哈希表进程资源索引算法
哈希表凭借O(1)查询效率、动态增删性能及低内存开销,适配电脑监控系统对进程资源数据的实时索引需求。通过定制哈希函数与链地址法冲突解决,实现高效进程状态追踪与异常预警。
335 10
|
存储 算法 安全
如何控制上网行为——基于 C# 实现布隆过滤器算法的上网行为管控策略研究与实践解析
在数字化办公生态系统中,企业对员工网络行为的精细化管理已成为保障网络安全、提升组织效能的核心命题。如何在有效防范恶意网站访问、数据泄露风险的同时,避免过度管控对正常业务运作的负面影响,构成了企业网络安全领域的重要研究方向。在此背景下,数据结构与算法作为底层技术支撑,其重要性愈发凸显。本文将以布隆过滤器算法为研究对象,基于 C# 编程语言开展理论分析与工程实践,系统探讨该算法在企业上网行为管理中的应用范式。
332 8
|
机器学习/深度学习 监控 算法
员工上网行为监控软件中基于滑动窗口的C#流量统计算法解析​
在数字化办公环境中,员工上网行为监控软件需要高效处理海量网络请求数据,同时实时识别异常行为(如高频访问非工作网站)。传统的时间序列统计方法因计算复杂度过高,难以满足低延迟需求。本文将介绍一种基于滑动窗口的C#统计算法,通过动态时间窗口管理,实现高效的行为模式分析与流量计数。
369 2
|
11月前
|
存储 监控 安全
企业上网监控系统中红黑树数据结构的 Python 算法实现与应用研究
企业上网监控系统需高效处理海量数据,传统数据结构存在性能瓶颈。红黑树通过自平衡机制,确保查找、插入、删除操作的时间复杂度稳定在 O(log n),适用于网络记录存储、设备信息维护及安全事件排序等场景。本文分析红黑树的理论基础、应用场景及 Python 实现,并探讨其在企业监控系统中的实践价值,提升系统性能与稳定性。
694 1
|
12月前
|
监控 算法 数据处理
内网实时监控中的 C# 算法探索:环形缓冲区在实时数据处理中的关键作用
本文探讨了环形缓冲区在内网实时监控中的应用,结合C#实现方案,分析其原理与优势。作为固定长度的循环队列,环形缓冲区通过FIFO机制高效处理高速数据流,具备O(1)时间复杂度的读写操作,降低延迟与内存开销。文章从设计逻辑、代码示例到实际适配效果展开讨论,并展望其与AI结合的潜力,为开发者提供参考。
453 2
|
12月前
|
监控 算法 安全
公司电脑监控软件关键技术探析:C# 环形缓冲区算法的理论与实践
环形缓冲区(Ring Buffer)是企业信息安全管理中电脑监控系统设计的核心数据结构,适用于高并发、高速率与短时有效的多源异构数据处理场景。其通过固定大小的连续内存空间实现闭环存储,具备内存优化、操作高效、数据时效管理和并发支持等优势。文章以C#语言为例,展示了线程安全的环形缓冲区实现,并结合URL访问记录监控应用场景,分析了其在流量削峰、关键数据保护和高性能处理中的适配性。该结构在日志捕获和事件缓冲中表现出色,对提升监控系统效能具有重要价值。
342 1
|
11月前
|
存储 搜索推荐 算法
加密算法、排序算法、字符串处理及搜索算法详解
本文涵盖四大类核心技术知识。加密算法部分介绍了对称加密(如 AES)、非对称加密(如 RSA)、哈希摘要(如 SHA-2)、签名算法的特点及密码存储方案(加盐、BCrypt 等)。 排序算法部分分类讲解了比较排序(冒泡、选择、插入、归并、快排、堆排序)和非比较排序(计数、桶、基数排序)的时间复杂度、适用场景及实现思路,强调混合排序的工业应用。 字符串处理部分包括字符串反转的双指针法,及项目中用正则进行表单校验、网页爬取、日志处理的实例。 搜索算法部分详解了二分查找的实现(双指针与中间索引计算)和回溯算法的概念(递归 + 剪枝),以 N 皇后问题为例说明回溯应用。内容全面覆盖算法原理与实践
309 0
|
11月前
|
存储 监控 算法
基于跳表数据结构的企业局域网监控异常连接实时检测 C++ 算法研究
跳表(Skip List)是一种基于概率的数据结构,适用于企业局域网监控中海量连接记录的高效处理。其通过多层索引机制实现快速查找、插入和删除操作,时间复杂度为 $O(\log n)$,优于链表和平衡树。跳表在异常连接识别、黑名单管理和历史记录溯源等场景中表现出色,具备实现简单、支持范围查询等优势,是企业网络监控中动态数据管理的理想选择。
277 0
|
存储 监控 算法
局域网上网记录监控的 C# 基数树算法高效检索方案研究
在企业网络管理与信息安全领域,局域网上网记录监控是维护网络安全、规范网络行为的关键举措。随着企业网络数据量呈指数级增长,如何高效存储和检索上网记录数据成为亟待解决的核心问题。基数树(Trie 树)作为一种独特的数据结构,凭借其在字符串处理方面的卓越性能,为局域网上网记录监控提供了创新的解决方案。本文将深入剖析基数树算法的原理,并通过 C# 语言实现的代码示例,阐述其在局域网上网记录监控场景中的具体应用。
274 7
|
存储 算法 Java
算法系列之数据结构-二叉树
树是一种重要的非线性数据结构,广泛应用于各种算法和应用中。本文介绍了树的基本概念、常见类型(如二叉树、满二叉树、完全二叉树、平衡二叉树、B树等)及其在Java中的实现。通过递归方法实现了二叉树的前序、中序、后序和层次遍历,并展示了具体的代码示例和运行结果。掌握树结构有助于提高编程能力,优化算法设计。
477 10
 算法系列之数据结构-二叉树