C#数据结构-八大排序算法

阅读目录

1. 冒泡排序
2. 选择排序
3. 插入排序
4. 希尔排序
5. 快速排序:初始快速排序、三向切分的快速排序(快速排序的优化版)
6. 堆排序
7. 归并排序:数组版本、List版本
8. 桶排序

下面所有的代码,都已经经过vs测试。

首先,通用的交换函数Swap:

private static void Swap(ref int a, ref int b)
{
    int temp = a;
    a = b;
    b = temp;
}

1. 冒泡排序

基本思想:依次比较相邻的两个元素,如果前面的数据大于后面的数据,就将两个数据进行交换

C#算法实现:

/// 
        /// 冒泡排序
        /// 依次比较相邻的两个元素,如果前面的数据大于后面的数据,就将两个数据进行交换
        /// 测试用例:4 3 2 1
        /// i = 0; 
        /// j = 1; 3 4 2 1
        /// j = 2; 3 2 4 1
        /// j = 3; 3 2 1 4
        /// 
        /// i = 1;
        /// j = 1; 2 3 1 4
        /// j = 2; 2 1 3 4
        /// 
        /// i = 2;
        /// j = 1; 1 2 3 4
        /// 
        private static void BubbleSort(int[] arr, int length)
        {
            for (int i = 0; i < length - 1; i++)
            {
                for (int j = 1; j < length - i; j++)
                {
                    if (arr[j] < arr[j - 1])
                    {
                        Swap(ref arr[j - 1], ref arr[j]);
                    }
                }
            }
        }

2. 选择排序

基本思想:在要排序的一组数中,假设第一个元素时最小值,依次与后面的元素比较,如果有更小的值,交换。继续遍历元素,依次找到最小的值,进行交换,最后完成排序。

C#算法实现:

/// 
        /// 选择排序
        /// 在要排序的一组数中,选出最小的一个数与第i个位置的数交换,之后依次类推(i=0,1,2,3...)
        /// 测试用例:49 38 65 32
        /// i = 0,min = 3, 32 38 65 49
        /// i = 1, min = 1, 32 38 65 49
        /// i = 2, min = 3, 32 38 49 65
        /// 
        private static void SelectSort(int[] arr, int length)
        {
            for (int i = 0; i < length - 1; i++)
            {
                int min = i;
                for (int j = i + 1; j < length; j++)
                {
                    if (arr[j] < arr[min])
                    {
                        min = j;
                    }
                }
                //当在此次遍历中,如果没有比arr[i]更小的值,则不用交换
                if (min != i)
                {
                    Swap(ref arr[i], ref arr[min]);
                }
            }
        }

3. 插入排序

基本思想:将原来的无序数列看成含有一个元素的有序序列和一个无序序列,将无序序列中的值依次插入到有序序列中,完成排序。

C#算法实现:

/// 
        /// 插入排序
        /// 将原来的无序数列看成含有一个元素的有序序列和一个无序序列,将无序序列中的值依次插入到有序序列中,完成排序
        /// 测试用例: 49 38 65 32
        /// i = 1, j = 0; a[0] > a[1] YES 交换 38 49 65 32
        /// i = 2, j = 1; a[1] > a[2] NO 不交换
        /// i = 2, j = 0; a[0] > a[1] NO 不交换
        /// i = 3, j = 2; a[2] > a[3] YES 交换 38 49 32 65
        /// i = 3, j = 1; a[1] > a[2] YES 交换 38 32 49 65
        /// i = 3, j = 0; a[0] > a[1] YES 交换 32 38 49 65
        /// 
        private static void InsertionSort(int[] arr, int length)
        {
            //将a[0]作为有序序列,从索引1开始遍历无序序列
            for (int i = 1; i < length; i++)
            {
                for (int j = i - 1; j >= 0 && arr[j] > arr[j + 1]; j--)
                {
                    Swap(ref arr[j], ref arr[j + 1]);
                }
            }
        }

4. 希尔排序

基本思想:在插入排序的基础上加入了分组策略,将数组序列分成若干子序列分别进行插入排序。

C#算法实现:

/// 
        /// 希尔排序
        /// 在插入排序的基础上加入了分组策略
        /// 将数组序列分成若干子序列分别进行插入排序
        /// 测试用例: 49 38 65 32
        /// gap = 2;
        /// i = 2, j = 0; a[0] > a[2] NO
        /// i = 3, j = 1; a[1] > a[3] YES 交换 49 32 65 38
        /// 
        /// gap = 1;
        /// i = 1, j = 0; a[0] > a[1] YES 交换 32 49 65 38
        /// i = 2, j = 1; a[1] > a[2] NO
        /// i = 3, j = 2; a[2] > a[3] YES 交换 32 49 38 65
        /// i = 3, j = 1; a[1] > a[2] YES 交换 32 38 49 65
        /// i = 3, j = 0; a[0] > a[1] NO
        /// 
        /// 
        /// 
        private static void ShellSort(int[] arr, int length)
        {
            for (int gap = length / 2; gap > 0; gap = gap / 2)
            {
                //插入排序
                for (int i = gap; i < length; i++)
                {
                    for (int j = i - gap; j >= 0 && arr[j] > arr[j + gap]; j -= gap)
                    {
                        Swap(ref arr[j], ref arr[j + gap]);
                    }
                }
            }
        }

5. 快速排序

基本思想:采用分治的思想,对数组进行排序,每次排序都使得操作的数组部分分成以某个元素为分界值的两部分,一部分小于分界值,另一部分大于分界值。分界值一般称为“轴”。一般是以第一个元素为轴,将数组分成左右两部分,然后对左右两部分递归操作,直至完成排序。

C#算法实现:

/// 
        /// 快速排序
        /// 采用分治的思想,对数组进行排序,每次排序都使得操作的数组部分
        /// 分成以某个元素为分界值的两部分,一部分小于分界值,另一部分大于分界值。分界值一般称为“轴”
        /// 一般是以第一个元素为轴,将数组分成左右两部分,然后对左右两部分递归操作,直至完成排序。
        /// 测试用例: 14 11 25 37 9 28
        /// 1.以第一个元素L = 0为最初的轴,pivot = 14
        /// 2.从下标R = 5开始,从后向前找到比pivot 14小的数9,此时L = 0,R = 4,赋值给arr[L] = arr[R], L++
        ///   9 11 25 37 9 28
        /// 3.从下标L = 1开始,从前向后找到比pivot 14大的数25,此时L = 2,R = 4,赋值给arr[R] = arr[L],R--
        ///   9 11 25 37 25 28
        /// 4.在新的L = 2位置上设置新的轴, pivot = 14, arr[L] = pivot
        ///   9 11 14 37 25 28
        /// 5.然后,对比新的轴小的部分和比新的轴大的部分分别递归排序,直至完成排序
        /// 
        /// 
        /// 数组的0下标
        /// 数组的Length - 1下标
        private static void QuickSort(int[] arr, int left, int right)
        {
            if (left < right)
            {
                int L = left;
                int R = right;
                int pivot = arr[L];
                while (L < R)
                {
                    //从后向前找出比pivot小的数
                    while (L < R && arr[R] > pivot)
                    {
                        R--;
                    }
                    //找到比pivot小的数,赋值给arr[L]
                    if (L < R)
                    {
                        arr[L] = arr[R];
                        L++;
                    }
                    //从前向后找出比pivot大的数
                    while (L < R && arr[L] < pivot)
                    {
                        L++;
                    }
                    //找到比pivot大的数,赋值给arr[R], 也就是之前比pivot小的数的位置
                    if (L < R)
                    {
                        arr[R] = arr[L];
                        R--;
                    }
                }
                //在新的L位置设置新的轴
                arr[L] = pivot;
                //对比新的轴小的部分递归排序
                QuickSort(arr, left, L - 1);
                //对比新的轴大的部分递归排序
                QuickSort(arr, L + 1, right);
            }
        }

三向切分的快速排序

快速排序在实际应用中会面对大量具有重复元素的数组。相比原生的快排,有巨大的改进潜力。(从O(nlgn)提升到O(n))
E.W.Dijlstra(对,就是Dijkstra最短路径算法的发明者)提出的算法是:

对于每次切分:从数组的左边到右边遍历一次,维护三个指针,其中lt指针使得元素(arr[0]-arr[lt-1])的值均小于切分元素;gt指针使得元素(arr[gt+1]-arr[N-1])的值均大于切分元素;i指针使得元素(arr[lt]-arr[i-1])的值均等于切分元素,(arr[i]-arr[gt])的元素还没被扫描,切分算法执行到i>gt为止。每次切分之后,位于gt指针和lt指针之间的元素的位置都已经被排定,不需要再去处理了。之后将(lo,lt-1),(gt+1,hi)分别作为处理左子数组和右子数组的递归函数的参数传入,递归结束,整个算法也就结束。

三向切分的示意图:

C#数据结构-八大排序算法_第1张图片

/// 
        ///  快速排序在实际应用中会面对大量具有重复元素的数组。相比原生的快排,有巨大的改进潜力。(从O(nlgn)提升到O(n))
        ///  E.W.Dijlstra(对,就是Dijkstra最短路径算法的发明者)提出的算法是: 对于每次切分:从数组的左边到右边遍历一次,维护三个指针,
        ///  其中lt指针使得元素(arr[0]-arr[lt-1])的值均小于切分元素;gt指针使得元素(arr[gt+1]-arr[N-1])的值均大于切分元素;
        ///  i指针使得元素(arr[lt]-arr[i-1])的值均等于切分元素,(arr[i]-arr[gt])的元素还没被扫描,切分算法执行到i>gt为止。
        ///  每次切分之后,位于gt指针和lt指针之间的元素的位置都已经被排定,不需要再去处理了。
        ///  之后将(lo,lt-1),(gt+1,hi)分别作为处理左子数组和右子数组的递归函数的参数传入,递归结束,整个算法也就结束。
        /// 
        /// 
        /// 
        /// arr.Length - 1
        private static void QuickSort_Optimization(int[] arr, int low, int hi)
        {
            //去除单个元素或者没有元素的情况
            if (low < hi)
            {
                int lt = low;
                int i = low + 1;//第一个元素是切分元素,所以i从low+1开始
                int gt = hi;
                int pivot = arr[lt];
                while (i <= gt)
                {
                    //小于切分元素放在lt左边,指针lt和i整体右移
                    if (arr[i] < pivot)
                    {
                        Swap(ref arr[i], ref arr[lt]);
                        i++;
                        lt++;
                    }
                    //大于切分元素放在gt右边,指针gt左移
                    else if (arr[i] > pivot)
                    {
                        Swap(ref arr[i], ref arr[gt]);
                        gt--;
                    }
                    //等于切分元素,指针i++
                    else
                    {
                        i++;
                    }
                }
                //lt-gt之间的元素已经排定,只需对lt左边和gt右边的元素进行递归排序
                //对比新的轴小的部分递归排序
                QuickSort_Optimization(arr, low, lt - 1);
                //对比新的轴大的部分递归排序
                QuickSort_Optimization(arr, gt + 1, hi);
            }
        }

6. 堆排序

基本思想:堆对应一棵完全二叉树,且所有非叶结点的值均不大于(或不小于)其子女的值,根结点(堆顶元素)的值是最小(或最大)的,每次都取堆顶的元素,将其放在序列最后面,然后将剩余的元素重新调整为最小(大)堆,依次类推,最终得到排序的序列。

堆排序分为大顶堆和小顶堆排序。大顶堆:堆对应一棵完全二叉树,且所有非叶结点的值均不小于其子女的值,根结点(堆顶元素)的值是最大的。而小顶堆正好相反,小顶堆:堆对应一棵完全二叉树,且所有非叶结点的值均不大于其子女的值,根结点(堆顶元素)的值是最小的

举个例子:

(a)大顶堆序列:(96, 83,27,38,11,09)

(b)小顶堆序列:(12,36,24,85,47,30,53,91)

C#数据结构-八大排序算法_第2张图片

实现堆排序需解决两个问题:
  1. 如何将n 个待排序的数建成堆?

  2. 输出堆顶元素后,怎样调整剩余n-1 个元素,使其成为一个新堆?

首先讨论第二个问题:输出堆顶元素后,怎样对剩余n-1元素重新建成堆?

调整小顶堆的方法:
  1)设有m 个元素的堆,输出堆顶元素后,剩下m-1 个元素。将堆底元素送入堆顶((最后一个元素与堆顶进行交换),堆被破坏,其原因仅是根结点不满足堆的性质。
  2)将根结点与左、右子树中较小元素的进行交换。
  3)若与左子树交换:如果左子树堆被破坏,即左子树的根结点不满足堆的性质,则重复方法 (2).
  4)若与右子树交换,如果右子树堆被破坏,即右子树的根结点不满足堆的性质。则重复方法 (2).
  5)继续对不满足堆性质的子树进行上述交换操作,直到叶子结点,堆被建成。

  称这个自根结点到叶子结点的调整过程为筛选。如图:

C#数据结构-八大排序算法_第3张图片

再讨论第一个问题,如何将n 个待排序元素初始建堆?
  建堆方法:对初始序列建堆的过程,就是一个反复进行筛选的过程。
  1)n 个结点的完全二叉树,则最后一个结点是第n/2个结点的子树。
  2)筛选从第n/2个结点为根的子树开始,该子树成为堆。
  3)之后向前依次对各结点为根的子树进行筛选,使之成为堆,直到根结点。

  如图建堆初始过程:无序序列:(49,38,65,97,76,13,27,49)

C#数据结构-八大排序算法_第4张图片

C#算法实现:

/// 
        /// 堆排序
        /// 堆对应一棵完全二叉树,且所有非叶结点的值均不大于(或不小于)其子女的值,根结点(堆顶元素)的值是最小(或最大)的
        /// 每次都取堆顶的元素,将其放在序列最后面,然后将剩余的元素重新调整为最小堆,依次类推,最终得到排序的序列。
        /// 
        /// 
        /// 
        private static void HeapSort(int[] arr, int length)
        {
            CreateHeap(arr, length);
            //从最后的节点进行调整
            for (int i = length - 1; i > 0; i--)
            {
                //交换堆顶和最后一个节点的元素
                Swap(ref arr[0], ref arr[i]);
                //每次交换进行调整
                AdjustHeap(arr, 0, i - 1);
            }
        }

        /// 
        /// 建堆方法:对初始序列建堆的过程,就是一个反复进行筛选的过程。
        /// 1)n 个结点的完全二叉树,则最后一个结点是第n/2个结点的子树。
        /// 2)筛选从第n/2个结点为根的子树开始,该子树成为堆。
        /// 3)之后向前依次对各结点为根的子树进行筛选,使之成为堆,直到根结点。
        /// 完全二叉树:除最后一层外,每一层上的结点数均达到最大值;在最后一层上只缺少右边的若干结点。
        /// 
        private static void CreateHeap(int[] arr, int length)
        {
            for (int i = length / 2 - 1; i >= 0; i--)
            {
                AdjustHeap(arr, i, length - 1);
            }
        }

        private static void AdjustHeap(int[] arr, int start, int length)
        {
            int root = start;
            int child = root * 2 + 1;
            while (child <= length)
            {
                //若子节点指标在范围内才做比较
                if (child + 1 <= length && arr[child] < arr[child + 1])
                {
                    //先比较两个子节点大小,选择最大的
                    child++;
                }
                //如果父节点大於子节点代表调整完毕,直接跳出函数
                if (arr[root] > arr[child])
                {
                    return;
                }
                else
                { 
                    //否则交换父子内容再继续子节点和孙节点比较
                    Swap(ref arr[root], ref arr[child]);
                    root = child;
                    child = root * 2 + 1;
                }
            }
        }

堆排序,还有一个扩展知识,二叉堆,对应一棵完全二叉树,且所有非叶结点的值均不大于(或不小于)其子女的值,根结点(堆顶元素)的值是最小(或最大)的。更多实现:C#数据结构-二叉堆实现

7. 归并排序

基本思想:将两个(或两个以上)有序表合并成一个新的有序表。

C#算法实现, 数组版本:

/// 
        /// 归并排序 递归版本
        /// 将两个(或两个以上)有序表合并成一个新的有序表
        /// 
        private static void MergeSort(int[] arr, int length)
        {
            int[] temp = new int[length];
            MergeInternalSort(arr, 0, length, temp);
        }

        private static void MergeInternalSort(int[] arr, int first, int last, int[] temp)
        {
            if (first < last)
            {
                int mid = (first + last) / 2;
                MergeInternalSort(arr, first, mid, temp);
                MergeInternalSort(arr, mid + 1, last, temp);
                Merge(arr, first, mid, last, temp);
            }
        }

       private static void Merge(int[] arr, int first, int mid, int last, int[] temp)
        {
                int i = first;
                int j = mid + 1;
                int k = 0;
                //通过比较,把较小的一部分数放入到temp数组中
                while (i <= mid && j <= last)
                {
                    if (arr[i] < arr[j])
                    {
                        temp[k++] = arr[i++];
                    }
                    else
                    {
                        temp[k++] = arr[j++];
                    }
                }
                //将数组剩余的数放入到temp数组中
                while (i <= mid)
                {
                    temp[k++] = arr[i++];
                }
                while (j <= last)
                {
                    temp[k++] = arr[j++];
                }
                //把合并的数组结果赋值给原数组
                for (int m = 0; m < k; m++)
                {
                    arr[m + first] = temp[m];
                }
         }

C#算法实现, List版本:

/// 
        /// 归并排序 List版本
        /// 将两个(或两个以上)有序表合并成一个新的有序表
        /// 
        public static List MergeSort(List list)
        {
            int count = list.Count;
            if (count <= 1)
            {
                return list;
            }
            int mid = count / 2;
            List left = new List();//定义左侧List
            List right = new List();//定义右侧List

            //以下两个循环把list分为左右两个List
            for (int i = 0; i < mid; i++)
            {
                left.Add(list[i]);
            }
            for (int j = mid; j < count; j++)
            {
                right.Add(list[j]);
            }
            left = MergeSort(left);
            right = MergeSort(right);
            return Merge(left, right);
        }
        /// 
        /// 合并两个已经排好序的List
        /// 
        /// 左侧List
        /// 右侧List
        /// 
        static List Merge(List left, List right)
        {
            List temp = new List();
            while (left.Count > 0 && right.Count > 0)
            {
                if (left[0] <= right[0])
                {
                    temp.Add(left[0]);
                    left.RemoveAt(0);
                }
                else
                {
                    temp.Add(right[0]);
                    right.RemoveAt(0);
                }
            }
            if (left.Count > 0)
            {
                for (int i = 0; i < left.Count; i++)
                {
                    temp.Add(left[i]);
                }
            }
            if (right.Count > 0)
            {
                for (int i = 0; i < right.Count; i++)
                {
                    temp.Add(right[i]);
                }
            }
            return temp;
        }

8. 桶排序

基本思想:类似于哈希表的拉链法,定义一个映射函数,将值放入对应的桶中,可以参考上文哈希查找。

C#算法实现:

/// 
        /// 桶排序
        /// 类似于哈希表的拉链法,定义一个映射函数,将值放入对应的桶中
        /// 最坏时间情况:全部分到一个桶中O(N^2),一般情况为O(NlogN)
        /// 最好时间情况:每个桶中只有一个数据时最优O(N)
        /// int bucketNum = arr.Length;
        /// 映射函数:int bucketIndex = arr[i] * bucketNum / (max + 1);
        /// 
        /// 
        /// 数组的最大值
        /// 
        private static int[] BucketSort(int[] arr, int max, int min)
        {
            int bucketNum = arr.Length;

            // 初始化桶  
            LinkedList[] bucket = new LinkedList[arr.Length];
            for (int i = 0; i < bucketNum; i++)
            {
                bucket[i] = new LinkedList();
            }
            // 元素分装各个桶中  
            for (int i = 0; i < bucketNum; i++)
            {
                //映射函数
                int bucketIndex = arr[i] * bucketNum / (max + 1);
                InsertIntoLinkList(bucket[bucketIndex], arr[i]);
            }
            // 从各个桶中获取后排序插入  
            int index = 0;
            for (int i = 0; i < bucketNum; i++)
            {
                foreach (var item in bucket[i])
                {
                    arr[index++] = item;
                }
            }
            return arr;
        }

        ///   
        /// 按升序插入 linklist   
        ///   
        ///  要排序的链表   
        ///  要插入排序的数字   
        private static void InsertIntoLinkList(LinkedList linkedList, int num)
        {
            // 链表为空时,插入到第一位  
            if (linkedList.Count == 0)
            {
                linkedList.AddFirst(num);
                return;
            }
            else
            {
                foreach (int i in linkedList)
                {
                    if (i > num)
                    {
                        System.Collections.Generic.LinkedListNode node = linkedList.Find(i);
                        linkedList.AddBefore(node, num);
                        return;
                    }
                }
                linkedList.AddLast(num);
            }
        }

最后附上,测试用例代码:

static void Main(string[] args)
        {
            Console.WriteLine("冒泡排序:");
            int[] arr = { 1, 3, 4, 6, 9, 10, 32, 45, 2, 5 };
            BubbleSort(arr, arr.Length);
            Show(arr);

            Console.WriteLine("\n选择排序:");
            int[] temp1 = { 1, 3, 4, 6, 9, 10, 32, 45, 2, 5 };
            SelectSort(temp1, temp1.Length);
            Show(temp1);

            Console.WriteLine("\n快速排序:");
            int[] temp2 = { 1, 3, 4, 6, 9, 10, 32, 45, 2, 5 };
            QuickSort(temp2, 0, temp2.Length - 1);
            Show(temp2);

            Console.WriteLine("\n快速排序优化:");
            int[] temp8 = { 1, 3, 4, 6, 9, 10, 32, 45, 2, 5, 5, 5, 5, 5 };
            QuickSort_Optimization(temp8, 0, temp8.Length - 1);
            Show(temp8);

            Console.WriteLine("\n插入排序:");
            int[] temp3 = { 1, 3, 4, 6, 9, 10, 32, 45, 2, 5 };
            InsertionSort(temp3, temp3.Length);
            Show(temp3);

            Console.WriteLine("\n希尔排序:");
            int[] temp4 = { 1, 3, 4, 6, 9, 10, 32, 45, 2, 5 };
            ShellSort(temp4, temp4.Length);
            Show(temp4);

            Console.WriteLine("\n堆排序:");
            int[] temp5 = { 1, 3, 4, 6, 9, 10, 32, 45, 2, 5 };
            HeapSort(temp5, temp5.Length);
            Show(temp5);

            Console.WriteLine("\n归并排序:");
            int[] temp6 = { 1, 3, 4, 6, 9, 10, 32, 45, 2, 5 };
            MergeSort(temp6, temp6.Length);
            Show(temp6);

            Console.WriteLine("\n桶排序:");
            int[] temp7 = { 1, 3, 4, 6, 9, 10, 32, 45, 2, 5 };
            //注:这里后两个参数传入的是数组的最大值,最小值
            BucketSort(temp7, 45, 1);
            Show(temp7);

            Console.ReadLine();
        }

        private static void Show(int[] arr)
        {
            int length = arr.Length;
            for (int i = 0; i < length; i++)
            {
                Console.Write(arr[i] + " ");
            }
        }

执行结果:

C#数据结构-八大排序算法_第5张图片

C#数据结构-八大排序算法_第6张图片

(1)当原表有序或基本有序时,直接插入排序和冒泡排序将大大减少比较次数和移动记录的次数,时间复杂度可降至O(n);

(2)而快速排序则相反,当原表基本有序时,将蜕化为冒泡排序,时间复杂度提高为O(n^2);

(3)原表是否有序,对简单选择排序、堆排序、归并排序和基数排序的时间复杂度影响不大。

每种排序算法都各有优缺点。因此,在实用时需根据不同情况适当选用,甚至可以将多种方法结合起来使用。

  选择排序算法的依据:

  影响排序的因素有很多,平均时间复杂度低的算法并不一定就是最优的。相反,有时平均时间复杂度高的算法可能更适合某些特殊情况。同时,选择算法时还得考虑它的可读性,以利于软件的维护。一般而言,需要考虑的因素有以下四点:

  (1)待排序的记录数目n的大小;

  (2)记录本身数据量的大小,也就是记录中除关键字外的其他信息量的大小;

  (3)关键字的结构及其分布情况;

  (4)对排序稳定性的要求。

  设待排序元素的个数为n.

  (1)当n较大,则应采用时间复杂度为O(n*logn)的排序方法:快速排序、堆排序或归并排序。

    快速排序:是目前基于比较的内部排序中被认为是最好的方法,当待排序的关键字是随机分布时,快速排序的平均时间最短;

    堆排序:如果内存空间允许且要求稳定性的;

    归并排序:它有一定数量的数据移动,所以我们可能过与插入排序组合,先获得一定长度的序列,然后再合并,在效率上将有所提高。

  (2)当n较大,内存空间允许,且要求稳定性:归并排序

  (3)当n较小,可采用直接插入或直接选择排序。

      直接插入排序:当元素分布有序,直接插入排序将大大减少比较次数和移动记录的次数。

      直接选择排序:当元素分布有序,如果不要求稳定性,选择直接选择排序。

  (4)一般不使用或不直接使用传统的冒泡排序。

 

最后附上,旧金山大学计算机系的一个网站,可以用非常形象的动画展示,各种排序算法的执行过程,超链接地址

   

除了以上这些排序算法,其实还有很多其他的算法,比如C#List的排序,内省排序

  • 如果分区大小少于16个元素,则使用插入排序算法。

  • 如果分区数量超过2 * LogN,其中N是输入数组的范围,则它使用Heapsort算法

  • 否则,它使用Quicksort算法

附上:前辈大神的博客,更详细的算法细节,可以参考。

[Data Structure & Algorithm] 八大排序算法

【经典排序算法】八大排序对比总结

你可能感兴趣的:(C#,数据结构与算法)