Unity3d常用的排序算法时间复杂度与空间复杂度

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Unity3d常用的排序算法时间复杂度与空间复杂度相关的知识,希望对你有一定的参考价值。

参考技术A 常用的排序算法的时间复杂度与空间复杂度

1、时间复杂度
(1)时间频度 一个算法执行所耗费的时间,从理论上是不能算出来的,必须上机运行测试才能知道。但我们不可能也没有必要对每个算法都上机测试,只需知道哪个算法花费的时 间多,哪个算法花费的时间少就可以了。并且一个算法花费的时间与算法中语句的执行次数成正比例,哪个算法中语句执行次数多,它花费时间就多。一个算法中的 语句执行次数称为语句频度或时间频度。记为T(n)。
(2)时间复杂度 在刚才提到的时间频度中,n称为问题的规模,当n不断变化时,时间频度T(n)也会不断变化。但有时我们想知道它变化时呈现什么规律。为此,我们引入时间 复杂度概念。 一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,若有某个辅助函数f(n),使得当n趋近于无穷大 时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。
在各种不同算法中,若算法中语句执行次数为一个常数,则时间复杂度为O(1),另 外,在时间频度不相同时,时间复杂度有可能相同,如T(n)=n2+3n+4与T(n)=4n2+2n+1它们的频度不同,但时间复杂度相同,都为 O(n2)。 按数量级递增排列,常见的时间复杂度有:常数阶O(1),对数阶O(log2n),线性阶O(n), 线性对数阶O(nlog2n),平方阶O(n2),立方阶O(n3),..., k次方阶O(nk),指数阶O(2n)。随着问题规模n的不断增大,上述时间复杂度不断增大,算法的执行效率越低。 2、空间复杂度 与时间复杂度类似,空间复杂度是指算法在计算机内执行时所需存储空间的度量。记作: S(n)=O(f(n)) 我们一般所讨论的是除正常占用内存开销外的辅助存储单元规模。讨论方法与时间复杂度类似,不再赘述。
(3)渐进时间复杂度评价算法时间性能   主要用算法时间复杂度的数量级(即算法的渐近时间复杂度)评价一个算法的时间性能。
2、类似于时间复杂度的讨论,一个算法的空间复杂度(Space Complexity)S(n)定义为该算法所耗费的存储空间,它也是问题规模n的函数。渐近空间复杂度也常常简称为空间复杂度。
空 间复杂度(Space Complexity)是对一个算法在运行过程中临时占用存储空间大小的量度。一个算法在计算机存储器上所占用的存储空间,包括存储算法本身所占用的存储 空间,算法的输入输出数据所占用的存储空间和算法在运行过程中临时占用的存储空间这三个方面。算法的输入输出数据所占用的存储空间是由要解决的问题决定 的,是通过参数表由调用函数传递而来的,它不随本算法的不同而改变。存储算法本身所占用的存储空间与算法书写的长短成正比,要压缩这方面的存储空间,就必 须编写出较短的算法。算法在运行过程中临时占用的存储空间随算法的不同而异,有的算法只需要占用少量的临时工作单元,而且不随问题规模的大小而改变,我们 称这种算法是“就地/"进行的,是节省存储的算法,如这一节介绍过的几个算法都是如此;有的算法需要占用的临时工作单元数与解决问题的规模n有关,它随着 n的增大而增大,当n较大时,将占用较多的存储单元,例如将在第九章介绍的快速排序和归并排序算法就属于这种情况。
如当一个算法的空间复杂度为一个常量,即不随被处理数据量n的大小而改变时,可表示为O(1);当 一个算法的空间复杂度与以2为底的n的对数成正比时,可表示为0(10g2n);当一个算法的空I司复杂度与n成线性比例关系时,可表示为0(n).若形 参为数组,则只需要为它分配一个存储由实参传送来的一个地址指针的空间,即一个机器字长空间;若形参为引用方式,则也只需要为其分配存储一个地址的空间, 用它来存储对应实参变量的地址,以便由系统自动引用实参变量。

七种常用排序算法

七种常用排序算法

一、常见排序算法一览:

技术分享

时间复杂度: 是一个函数,它定量描述了该算法的运行时间。
空间复杂度:一个算法在运行过程中临时占用存储空间大小的量度。
稳定性:保证排序前2个相等的数其在序列的前后位置顺序和排序后它们两个的前后位置顺序相同就稳定,反之不稳定。

视觉直观感受 7 种常用的排序算法

二、算法C#实现:

1、 直接插入排序

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace csharpconsole
{
    class Program
    {
        /* 
        具体算法描述如下:
        1.从第一个元素开始,该元素可以认为已经被排序
        2.取出下一个元素,在已经排序的元素序列中从后向前扫描
        3.如果该元素(已排序)大于新元素,将该元素移到下一位置
        4.重复步骤3,直到找到已排序的元素小于或者等于新元素的位置
        5.将新元素插入到该位置后
        6.重复步骤2~5
        */
        public static void InsertSort(int[] List)
        {
            int tmp = 0;
            int len = List.Length;
            int i = 0;
            int j = 0;

            for (i = 1; i < len; i++)
            {
                tmp = List[i];
                for (j = i - 1; j >= 0; j--)
                {
                    if (tmp < List[j])
                    {
                        List[j + 1] = List[j];
                    }
                    else if (tmp > List[j])
                    {
                        break;
                    }
                }
                List[j + 1] = tmp;
            }
            return;
        }

        static void Main(string[] args)
        {
            int[] intArr = {10, 2, 56, 12, 6, 78, 34, 23, 9, 18, 7};

            InsertSort(intArr);

            for (int k = 0; k < intArr.Length; k++)
            Console.WriteLine(intArr[k]);
            Console.ReadKey();
        }
    }
}

2、 希尔排序
实际上是分组的插入排序。缩小增量排序。先取定一个小于n的整数d1作为第一个增量,把表的全部记录分成d1个组,所有距离为d1的倍数的记录放在同一个组中,在各组内进行直接插入排序;然后,取第二个增量d2(<d1),重复上述的分组和排序,直至所取的增量dt=1。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace csharpconsole
{
    class Program
    {
        public static void ShellSort(int[] List)
        {
            int tmp = 0;
            int len = List.Length;
            int i = 0;
            int j = 0;
            int d = len / 2; /* 初始步长取数组长度的一半 */

            /* 观察看如果d=1的话,即是普通的插入排序算法 */
            while (d >= 1)
            {
                /* 把距离为 d 的元素编为一个组,扫描所有组 */
                for (i = d; i < len; i++)
                {
                    tmp = List[i];

                    for (j = i - d; j >= 0; j = j - d)
                    {
                        if (tmp < List[j])
                        {
                            List[j + d] = List[j];
                        }
                        else if (tmp > List[j])
                        {
                            break;
                        }
                    }
                    List[j + d] = tmp;
                }

                d = d / 2;
            }


            return;
        }

        static void Main(string[] args)
        {
            int[] intArr = {10, 2, 56, 12, 6, 78, 34, 23, 9, 18, 7};

            ShellSort(intArr);

            for (int k = 0; k < intArr.Length; k++)
            Console.WriteLine(intArr[k]);
            Console.ReadKey();
        }
    }
}

3、冒泡排序(交换排序)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace csharpconsole
{
    class Program
    {
        public static void BubbleSort(int[] List)
        {
            int i = 0;
            int j = 0;
            int len = List.Length;
            int swap = 0;

            /* 
            第一趟排序:通过两两比较,找到第一小的数值 1 ,将其放在序列的第一位。
            第二趟排序:通过两两比较,找到第二小的数值 2 ,将其放在序列的第二位。
            第三趟排序:通过两两比较,找到第三小的数值 3 ,将其放在序列的第三位。
            至此,所有元素已经有序,排序结束。
            */
            for (i = len - 1; i >= 0; i--)
            {
                for (j = len - 1; j >= len - i; j--)
                {
                    if (List[j] < List[j - 1])
                    {
                        swap = List[j];
                        List[j] = List[j - 1];
                        List[j - 1] = swap;
                    }
                }
            }

            return;
        }

        static void Main(string[] args)
        {
            int[] intArr = {10, 2, 56, 12, 6, 78, 34, 23, 9, 18, 7};

            BubbleSort(intArr);

            for (int k = 0; k < intArr.Length; k++)
            Console.WriteLine(intArr[k]);
            Console.ReadKey();
        }
    }
}

4、 快速排序(交换排序)
步骤:
技术分享

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace csharpconsole
{
    class Program
    {
        public static void QuickSort(int[] List, int left, int right)
        {
            int baseNum = 0;
            int low = 0;
            int high = 0;

            if (left < right)
            {
                baseNum = List[left];
                low = left;
                high = right;

                while (low < high)
                {
                    /* 从右往左扫描 */
                    while ((high > low) && (baseNum < List[high]))
                    {
                        high--;
                    }
                    List[low] = List[high];

                    /* 从左往右扫描 */
                    while ((low < high) && (baseNum > List[high]))
                    {
                        low++;
                    }
                    List[high] = List[low];
                }

                List[low] = baseNum;
                QuickSort(List, left, low - 1);
                QuickSort(List, low + 1, right);
            }

            return;
        }

        static void Main(string[] args)
        {
            int[] intArr = {10, 2, 56, 12, 6, 78, 34, 23, 9, 18, 7};

            QuickSort(intArr, 0, intArr.Length - 1);

            for (int k = 0; k < intArr.Length; k++)
            Console.WriteLine(intArr[k]);
            Console.ReadKey();
        }
    }
}

5、简单选择排序(直接选择排序):
(1) 从待排序序列中,找到关键字最小的元素;
(2) 如果最小元素不是待排序序列的第一个元素,将其和第一个元素互换;
(3) 从余下的 N - 1 个元素中,找出关键字最小的元素,重复(1)、(2)步,直到排序结束。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace csharpconsole
{
    class Program
    {
        public static void SelectionSort(int[] List)
        {
            int index = 0;
            int swap = 0;
            int len = List.Length;
            int i = 0;
            int j = 0;

            for (; i < len; i++)
            {
                /* 找到这一趟循环最小的值,记录下标,默认下标为i */
                index = i;
                for (j = i + 1; j < len; j++)
                {
                    if (List[j] < List[index])
                    {
                        index = j;
                    }
                }

                /* 如果下标有改变,就交换数值 */
                if (index != i)
                {
                    swap = List[i];
                    List[i] = List[index];
                    List[index] = swap;
                }
            }

            return;
        }

        static void Main(string[] args)
        {
            int[] intArr = {10, 2, 56, 12, 6, 78, 34, 23, 9, 18, 7};

            SelectionSort(intArr);

            for (int k = 0; k < intArr.Length; k++)
            Console.WriteLine(intArr[k]);
            Console.ReadKey();
        }
    }
}

6、 堆排序
步骤:
(1)根据初始数组去构造初始堆(构建一个完全二叉树,保证所有的父结点都比它的孩子结点数值大)。
(2)每次交换第一个和最后一个元素,输出最后一个元素(最大值),然后把剩下元素重新调整为大根堆。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace csharpconsole
{
    class Program
    {
        public static void HeapAdjust(int[] array, int parent, int length)
        {

            int temp = array[parent]; // temp保存当前父节点
            int child = 2 * parent + 1; // 先获得左孩子

            while (child < length)
            {
                // 如果有右孩子结点,并且右孩子结点的值大于左孩子结点,则选取右孩子结点

                if (child + 1 < length && array[child] < array[child + 1])
                {
                    child++;
                }

                // 如果父结点的值已经大于孩子结点的值,则直接结束

                if (temp >= array[child])
                {
                    break;
                }

                // 把孩子结点的值赋给父结点
                array[parent] = array[child];

                // 选取孩子结点的左孩子结点,继续向下筛选
                parent = child;
                child = 2 * child + 1;
            }

            array[parent] = temp;
        }

        public static void HeapSort(int[] list)
        {
            // 循环建立初始堆
            for (int i = list.Length / 2; i >= 0; i--)
            {
                HeapAdjust(list, i, list.Length - 1);

            }

            // 进行n-1次循环,完成排序
            for (int i = list.Length - 1; i > 0; i--)
            {
                // 最后一个元素和第一元素进行交换
                int temp = list[i];
                list[i] = list[0];
                list[0] = temp;

                // 筛选 R[0] 结点,得到i-1个结点的堆
                HeapAdjust(list, 0, i);
            }

        }

        static void Main(string[] args)
        {
            int[] intArr = {10, 2, 56, 12, 6, 78, 34, 23, 9, 18, 7};

            HeapSort(intArr);

            for (int k = 0; k < intArr.Length; k++)
            Console.WriteLine(intArr[k]);
            Console.ReadKey();
        }
    }
}

7、 归并排序
步骤:
(1)“分解”——将序列每次折半划分。
(2)“合并”——将划分后的序列段两两合并后排序。

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace csharpconsole
{
    class Program
    {
        public static void Merge(int[] array, int low, int mid, int high)
        {
            int i = low; // i是第一段序列的下标
            int j = mid + 1; // j是第二段序列的下标
            int k = 0; // k是临时存放合并序列的下标
            int[] array2 = new int[high - low + 1]; // array2是临时合并序列

            // 扫描第一段和第二段序列,直到有一个扫描结束
            while (i <= mid && j <= high)
            {
                // 判断第一段和第二段取出的数哪个更小,将其存入合并序列,并继续向下扫描
                if (array[i] <= array[j])
                {
                    array2[k] = array[i];
                    i++;
                    k++;
                }
                else
                {
                    array2[k] = array[j];
                    j++;
                    k++;
                }
            }

            // 若第一段序列还没扫描完,将其全部复制到合并序列
            while (i <= mid)
            {
                array2[k] = array[i];
                i++;
                k++;
            }

            // 若第二段序列还没扫描完,将其全部复制到合并序列
            while (j <= high)
            {
                array2[k] = array[j];
                j++;
                k++;
            }

            // 将合并序列复制到原始序列中
            for (k = 0, i = low; i <= high; i++, k++)
            {
                array[i] = array2[k];
            }
        }

        public static void MergePass(int[] array, int gap, int length)
        {
            int i = 0;

            // 归并gap长度的两个相邻子表
            for (i = 0; i + 2 * gap - 1 < length; i = i + 2 * gap)
            {
                Merge(array, i, i + gap - 1, i + 2 * gap - 1);
            }

            // 余下两个子表,后者长度小于gap
            if (i + gap - 1 < length)
            {
                Merge(array, i, i + gap - 1, length - 1);
            }
        }

        public static int[] MergeSort(int[] list)
        {
            for (int gap = 1; gap < list.Length; gap = 2 * gap)
            {
                MergePass(list, gap, list.Length);
            }
            return list;
        }

        static void Main(string[] args)
        {
            int[] intArr = {10, 2, 56, 12, 6, 78, 34, 23, 9, 18, 7};

            MergeSort(intArr);

            for (int k = 0; k < intArr.Length; k++)
            Console.WriteLine(intArr[k]);
            Console.ReadKey();
        }
    }
}














以上是关于Unity3d常用的排序算法时间复杂度与空间复杂度的主要内容,如果未能解决你的问题,请参考以下文章

常用的排序算法的时间复杂度和空间复杂度

常用的排序算法的时间复杂度和空间复杂度

常用的排序算法的时间复杂度和空间复杂度

常用排序算法的Java实现与分析

常用排序算法的时间复杂度和空间复杂度

算法与数据结构:堆排序