Unity C#常用排序算法(归并、快排)的泛型写法(三)

7 篇文章 0 订阅
5 篇文章 0 订阅

目录

1.前言

2.归并排序

3.快速排序

4.总结


1.前言

承继初篇:Unity C#常用排序算法(冒泡、选择、插入)的泛型写法(一)

今天讲一下:归并排序和快速排序

2.归并排序

归并排序的思路:先将序列分成 n / 2份,进行两两比较排序,然后再对两个相邻的有序队列进行两两排序,以此类推直到排序完成;可以看成是一个完全二叉树,先对叶子节点进行两两排序,然后向上对子节点序列做排序,以此类推直到根节点结束;

从思路上看这是一个典型的递归实现过程,所以递归是它的一种解决方案

1.递归写法:

        /// <summary>
        /// 归并排序递归写法(升序)时间复杂度O(nlogn)(稳定排序),空间复杂度O(n + log2n)
        /// </summary>
        public static List<T> SortMargeRecursion<T>(List<T> list) where T : IComparerSort<T>
        {
            List<T> tempList = new List<T>(list);
            SortMargeRecursion(list, tempList, 0, list.Count - 1);
            return list;
        }

        private static void SortMargeRecursion<T>(List<T> list, List<T> tempList, int start, int end) where T : IComparerSort<T>
        {
            if (start >= end)
                return;
            int len = end - start;
            int mid = start + len / 2;
            SortMargeRecursion(list, tempList, start, mid);
            SortMargeRecursion(list, tempList, mid + 1, end);
            int i = start;
            int j = mid + 1;
            int k = start;
            while(i <= mid && j <= end)
            {
                if (list[i].Compare(list[i], list[j]) < 0)
                    tempList[k++] = list[i++];
                else
                    tempList[k++] = list[j++];
            }
            while(i <= mid)
            {
                tempList[k++] = list[i++];
            }
            while (j <= end)
            {
                tempList[k++] = list[j++];
            }
            for(i = start ; i <= end ; i++)
            {
                list[i] = tempList[i];
            }
        }

对于递归写法来说比较好理解,但是毕竟还有递归调用的时间和空间占用,所以下面还有一种非递归调用的写法

2.非递归写法:

        /// <summary>
        /// 归并排序(升序)时间复杂度O(nlogn)(稳定排序),空间复杂度O(n)
        /// </summary>
        public static List<T> SortMarge<T>(List<T> list) where T : IComparerSort<T>
        {
            int n = list.Count;
            List<T> tempList = new List<T>(list);
            List<T> temp;
            int low = 0;
            int mid = 0;
            int high = 0;
            int i = 0;
            int j = 0;
            int k = 0;
            for (int increase = 1 ; increase < n ; increase += increase)
            {
                for(int start = 0 ; start < n ; start += increase + increase)
                {
                    low = Min(start, n - 1);
                    mid = Min(start + increase, n - 1);
                    high = Min(start + increase + increase, n);
                    i = low;
                    j = mid;
                    k = low;
                    while(i < mid && j < high)
                    {
                        if (list[i].Compare(list[i], list[j]) < 0)
                            tempList[k++] = list[i++];
                        else
                            tempList[k++] = list[j++];
                    }
                    while(i < mid)
                    {
                        tempList[k++] = list[i++];
                    }
                    while(j < high)
                    {
                        tempList[k++] = list[j++];
                    }
                }
                temp = list;
                list = tempList;
                tempList = temp;
            }
            tempList.Clear();
            tempList = null;
            temp = null;
            return list;
        }

归并排序的最坏、最好、平均时间复杂度都是O(nlogn),空间复杂度是O(n+logn),归并排序是稳定排序,但是会有比较多的空间占用,在使用时要有取舍

3.快速排序

快速排序思路:通过一趟遍历找出一个枢纽位,使得枢纽位的左边都比它小,右边都比它大(左右这两个部分中并不需要有序),并返回这个枢纽位;然后对左右这两个部分再继续循环以上过程;

通过分析这显然也是一个递归的过程,这里枢纽位的选取有多种方式:取第一位、取最后一位、随机一位、找出前中后三位中处于中间数值的枢纽位

这里我们只介绍取第一个元素做枢纽位的写法:

        /// <summary>
        /// 快速排序(升序)时间复杂度O(nlogn)(非稳定排序),枢纽默认是第一个元素low
        /// </summary>
        public static List<T> SortQuick<T>(List<T> list) where T : IComparerSort<T>
        {
            SortQuick(list, 0, list.Count - 1);
            return list;
        }

        private static void SortQuick<T>(List<T> list, int start, int end) where T : IComparerSort<T>
        {
            if (start < end)
            {
                int low = start;
                int high = end;
                int pivot = low;
                T value = list[pivot];
                // 将枢纽pivot左右做简单排序,左的都比它小,右的都比它大
                while (low < high)
                {
                    while (pivot < high && list[high].Compare(list[high], value) >= 0)
                        high--;
                    if(pivot < high)
                    {
                        list[pivot] = list[high];
                        pivot = high;
                    }
                    while (pivot > low && list[low].Compare(list[low], value) <= 0)
                        low++;
                    if(pivot > low)
                    {
                        list[pivot] = list[low];
                        pivot = low;
                    }
                }
                list[pivot] = value;
                SortQuick(list, start, pivot - 1);
                SortQuick(list, pivot + 1, end);
            }
        }
 

注意:这里在将枢纽位左右做简单排序时,一定不要忘记 == 等于比较(如上 >= 0 和 <= 0),否则在有相同值元素的情况下会死循环

快排的时间复杂度是O(nlogn),它是非稳定排序,对于不强调稳定排序的情况下它一般来说都是最好的选择,否则用归并排序

4.总结

用三篇来大致描述了常用的7种排序泛型写法,这里主要是对思路做介绍,实现部分并不详尽也是希望大家可以在了解思路的情况下自行尝试去实现,理解更深刻。

7种排序的实现各自不同,但思路又有相同之处,例如:

1.希尔排序是基于直接插入排序的优化;

2.堆排可以看做选择排序的优化(大顶堆标记堆顶元素后,与末尾元素互换和简单选择排序的标记互换思路一样);

3.快排又可以看做是对冒泡的思路优化(在找枢纽位的同时,将大的元素向后冒泡,小的元素向前冒泡);

这里用到了如:二叉堆(大顶堆/小顶堆)、递归、分而治之、先粗(排序)后细(排序)等思路;这些思路不仅仅局限于排序算法,在功能开发中很多时候都可以用类似的思路来解决实际问题

 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity 中实现归并排序算法与在其他编程环境中实现类似。下面是一个使用归并排序算法对整数数组进行排序的示例: ```csharp using System; using UnityEngine; public class MergeSort : MonoBehaviour { void Start() { int[] arr = { 9, 5, 1, 8, 3, 6, 2, 7, 4 }; Debug.Log("Original array: "); PrintArray(arr); MergeSortAlgorithm(arr, 0, arr.Length - 1); Debug.Log("Sorted array: "); PrintArray(arr); } public void MergeSortAlgorithm(int[] arr, int left, int right) { if (left < right) { int mid = (left + right) / 2; MergeSortAlgorithm(arr, left, mid); MergeSortAlgorithm(arr, mid + 1, right); Merge(arr, left, mid, right); } } public void Merge(int[] arr, int left, int mid, int right) { int[] temp = new int[right - left + 1]; int i = left; int j = mid + 1; int k = 0; while (i <= mid && j <= right) { if (arr[i] <= arr[j]) { temp[k] = arr[i]; i++; } else { temp[k] = arr[j]; j++; } k++; } while (i <= mid) { temp[k] = arr[i]; i++; k++; } while (j <= right) { temp[k] = arr[j]; j++; k++; } for (int x = 0; x < temp.Length; x++) { arr[left + x] = temp[x]; } } public void PrintArray(int[] arr) { for (int i = 0; i < arr.Length; i++) { Debug.Log(arr[i] + " "); } Debug.Log(""); } } ``` 在上述示例中,我们使用一个整数数组来演示归并排序算法。首先,我们将数组分成两个子数组,然后递归地对每个子数组进行排序。最后,我们将两个已排序的子数组合并为一个有序的数组。 你可以根据需要修改代码以处理其他类型的输入数据。在 Unity 中,你可以在 MonoBehaviour 的 Start() 方法中调用归并排序算法并输出结果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值