美文网首页
排序算法总结

排序算法总结

作者: JervieQin | 来源:发表于2018-04-29 20:44 被阅读0次

    交换类排序

    冒泡排序精髓:
    设置一个两层循环。外层遍历次数为比较次数,内层从前往后遍历所有元素,当前者大于后者则交换位置。

    public void BubbleSort(int[] a)
            {
               int temp, upper = a.Length-1;
               for (int outer =1; outer<=upper; outer++)
                {
                    //每完成一次外层遍历,最大的肯定在最后,所以少遍历outer个元素
                    for (int inner = 0; inner <= upper-outer; inner++)
                    {
                        if (arr[inner] > arr[inner + 1])
                        {
                            temp = arr[inner];
                            arr[inner] = arr[inner + 1];
                            arr[inner + 1] = temp;
                        }
                    }
                }
            }
    

    #快速排序精髓(分治)
    将数组递归划分成两个子序列:设置pivot值,小于pivot的在pivot左边,大的在pivot右边。最先暂存的pivot值是为了给交换数值腾出位置,比较完后就附给中间值,因为比较都是以pivot来分大小,排左右的。

            public void QuickSort(int[] a,int low, int upper)
            {
               if (low< upper)
                {
                    int pivotIndex = Partition(a, low, upper);
                    //利用分之思想,将问题分成小块
                    QuickSort(a, low, pivotIndex- 1);
                    QuickSort(a, pivotIndex+ 1, upper);
                }
            }
    
            //划分子序列
            private int Partition(int[] a, int low, int upper)
            {
                int pivot = a[low];  //low作为比较的起点,暂存一下中轴值
                while (low< upper)//从两端交替向内扫描
                {
                     //low指针不动,upper指针扫描low右边
                    while (low< upper&& a[upper] >= pivot) 
                        upper--;
                    a[low] = a[upper];//将比pivot小的元素移向低端
    
                     //upper指针不动,low指针扫描upper左边
                    while (upper>low&& a[low] <= pivot)
                        low++;
                    a[upper] = a[low];//将比pivot大的元素移到高端
                }
                //low==high
                a[low] = pivot;  //将中轴元素附给中间这个位置
                return low;       //返回轴元素
            }
    

    处理大数据量且无序的排序问题,快速排序是最快的。.Net 框架库类中的 Sort 方法就是用快速排序算法实现的。另外,快排中的第一个pivot最好由arr[(int)arr.GetUpperBound(0) / 2]来确定(除非数组随机无序)

    选择类排序

    简单选择排序精髓
    设置两层循环。外层遍历所有元素,内层遍历外层之后元素,找到其中最小元素记录,然后和当前外层元素交换。

    public void SelectionSort(int[] a)
            {
                //O(N^2+N)
                int minIndex, temp, upper = a.Length-1;
                //遍历次数
                for (int outer = 0; outer <= upper; outer++)
                {
                    minIndex = outer;
                    //找到最小值索引
                    for (int inner = outer + 1; inner <= upper; inner++)
                    {
                        if (arr[inner] < arr[minIndex])
                            minIndex = inner;
                    }
                    //交换
                    temp = arr[outer];
                    arr[outer] = arr[minIndex];
                    arr[minIndex] = temp;
                  //  DisplayElements();
                }
            }
    

    插入类排序

    直接插入排序精髓
    把数组分为排好序的和没排好序的两半。设置两层循环,外层遍历第二个元素开始的所有元素,内层遍历排好序的元素。外层遍历元素在排序好的数中找位置:从后往前查找大于本身数直到有数小于本身,插入该位置。

     public void InsertSort(int[] a)
            {
                //O(N^2)
                int temp, inner;
                //遍历次数,从第二个数开始检查,第一个数默认有序
                for (int outer = 1; outer <= upper; outer++)
                {
                    temp = arr[outer];
                    inner = outer;
                    while (inner > 0 && arr[inner - 1] >= temp)  //数据后移
                    {
                        arr[inner] = arr[inner - 1];
                        inner -= 1;
                    }
                    arr[inner] = temp;
                    //DisplayElements();
                }
            }
    

    折半插入排序精髓
    在直接插入排序的基础上,有效的减少比较次数,但是移动次数并不会改变。设置两重循环,外层循环遍历第二个元素开始的所有数据,内层设置两个同级循环,一个用来折半遍历;另一个用来移动数据。

    public void BinInsertSort()
            {
                //所有待排序元素
                for (int i =  1; i <= upper; i++) 
                {
                    int temp = arr[i];
                    //前面有序子序列的范围
                    int hi = i - 1;int lo = 0;
    
                    while (lo <= hi)   //折半定位
                    {
                        int half = (lo + hi) / 2;
                        if (arr[half] < temp)
                            lo = half + 1;
                        else
                            hi = half - 1;
                    }
                    for (int j = i - 1; j > hi; j--)//移动
                        arr[j + 1] = arr[j];
                    arr[hi + 1] = temp;             //插入
                }
               // DisplayElements();
            }
    

    希尔排序(直接插入排序改进版)
    将待排序的元素分为多个子序列,使得每个子序列的元素个数相对较少,对各个子序列分别进行直接插入排序,待整个待排序序列“基本有序”后,再对所有元素进行一次直接插入排序。本算法的关键内容是对远距离而非相邻的数据项进行比较。当算法循环遍历数据集合的时候,每个数据项间的距离会缩短,直到算法对相邻数据项进行比较时才终止。

    public void ShellSort()
            {
                int inner, temp;
                int h = 3;    //步长
                while (h > 0)
                {
                    for (int outer = h; outer <= upper; outer++)
                    {
                        temp = arr[outer];
                        inner = outer;
                        while ((inner > h - 1) && arr[inner - h] >= temp)
                        {
                            arr[inner] = arr[inner - h];
                            inner -= h;
                        }
                        arr[inner] = temp;
                    }
                    h = (h - 1) % 3;    //缩短步长再次排序
                }
                //DisplayElements();
            }
    

    直接插入排序适合数据量少的情况下,后两个适合数据量大的的情况。同时,折半查找只是减少了比较次数、复杂度并没有降低。而希尔排序的复杂度受步长影响

    分治类排序(递归)

    1.快速排序(转上)
    2.归并排序
    这个算法把数据集合不断的分成两个部分,然后对每部分递归地进行
    排序。当两个部分都排序好时,再用合并程序把它们组合在一起。
    但是归并排序需要注意一个问题就是:划分出来的两个部分不一样长。这就要做一个规定:当主循环结束后,当且仅当两个数组中的一个数组还有元素时,可以使用两个额外的循环。

        /// <summary>
            /// 归并排序,分治法
            /// </summary>
            public void MergeSort()
            {
                //创建一个暂存数组,避免合并时反复申请内存
                int[] t = new int[arr.Length];
                Sort(arr,t, 0, arr.Length - 1);
                DisplayElements();
            }
    
            //递归排序
            public static void Sort(int[] a, int[] t, int low, int high)
            {
                if (low < high)
                {
                    //划分待排序列
                    int mid = (low + high) / 2;  
                    Sort(a,t, low, mid);
                    Sort(a,t, mid + 1, high);
    
                    //合并
                    Merge(a,t, low, mid, high);
                }
            }
            private static void Merge(int[] a, int[] t,int low, int mid, int high)
            {
                //m左序列起始指针,n右序列起始指针,k暂存数组起始指针
                int m = low, n = mid + 1, k = low;
    
                //比较左右两个序列上指针指的数字大小,小的先入数组
                while (n <= high && m <= mid)
                {
                    if (a[m] > a[n])
                        t[k++] = a[n++];
                    else
                        t[k++] = a[m++];
                }
    
                //如果两个子序列中有一个子序列先合并完了,把剩下的子序列全部加入暂存数组中
                //左序列还有剩下的
                while (n < high + 1)
                    t[k++] = a[n++];
                //右序列还有剩下的
                while (m < mid + 1)
                    t[k++] = a[m++];
    
                //把暂存数组里的数据再导回原来数组中
               for (int i = low; i <= high; i++)
                    a[i] = t[i];
            }
    

    为了形象化理解,参看图示:


    图示

    对比

    相关文章

      网友评论

          本文标题:排序算法总结

          本文链接:https://www.haomeiwen.com/subject/tskdkftx.html