zoukankan      html  css  js  c++  java
  • C#实现归并排序(递归,非递归,自然归并)

    源文件:http://pan.baidu.com/share/link?shareid=439730&uk=3912660076

    不足错误之处,还请您及时指出,谢谢。Email:wjshan0808@gmail.com

    //Main:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace Merge
    {
        class Program
        {
            static void Main(string[] args)
            {
                while (true)
                {
                    Console.WriteLine("请选择:");
                    Console.WriteLine("1.归并排序(非递归)");
                    Console.WriteLine("2.归并排序(递归)");
                    Console.WriteLine("3.归并排序(自然合并)");
                    Console.WriteLine("4.退出");
                    int Arraynum = Convert.ToInt32(Console.ReadLine());
                    switch (Arraynum)
                    {
                        case 4:
                            Environment.Exit(0);
                            break;
                        case 1:
                            Console.WriteLine("Please Input Array Length");
                            int Leng271 = Convert.ToInt32(Console.ReadLine());
                            Function obj1 = new Function(Leng271);
    
                            Console.WriteLine("The original sequence:");
                            Console.WriteLine(obj1);
                            Console.WriteLine("'MergeSort' Finaly Sorting Result:");
                            obj1.ToMergeSort();
                            Console.WriteLine(obj1);
                            break;
                        case 2:
                            Console.WriteLine("Please Input Array Length");
                            int Leng272 = Convert.ToInt32(Console.ReadLine());
                            Function obj2 = new Function(Leng272);
    
                            Console.WriteLine("The original sequence:");
                            Console.WriteLine(obj2);
                            Console.WriteLine("'RecursiveMergeSort' Finaly Sorting Result:");
                            obj2.ToRecursiveMergeSort();
                            Console.WriteLine(obj2);
                            break;
                        case 3:
                            Console.WriteLine("Please Input Array Length");
                            int Leng273 = Convert.ToInt32(Console.ReadLine());
                            Function obj3 = new Function(Leng273);
    
                            Console.WriteLine("The original sequence:");
                            Console.WriteLine(obj3);
                            obj3.ToNaturalMergeSort();
                            Console.WriteLine();Console.WriteLine();
                            Console.WriteLine("'NaturalMergeSort' Finaly Sorting Result:");
                            Console.WriteLine(obj3);
                            break;
                    }
                }
            }
        }
    }

    //Class:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    namespace Merge
    {
        // 【example 2.7】//抱歉,实在不知怎么学习英语,语法什么错误之处还请见谅。
        class Function
        {
            private int Groups;
            private int CopyGroups;
            private int mergerows;
            private int[] Array27;
            private static Random ran = new Random();
            public Function(int length)
            {
                Array27 = new int[length];
                for (int i = 0; i < length; i++)
                    Array27[i] = /*Convert.ToInt32(Console.ReadLine()); //*/ran.Next(1, 100);
            }
            //选择
            public void ToMergeSort()
            {
                MergeSort(Array27);
            }
            public void ToRecursiveMergeSort()
            {
                RecursiveMergeSort(Array27, 0, Array27.Length - 1);
            }
            public void ToNaturalMergeSort()
            {
                NaturalMergeSort(Array27);
            }
    
            /// <summary>
            /// 归并排序(递归)
            ///    核心思想:(分治)
            ///           将待排序元素(递归直至元素个数为1)分成左右两个大小大致相同的2个子集合,然后,
            ///           分别对2个子集合进行排序,最终将排好序的子集合合并成为所要求的排好序的集合.  
            /// 核心算法时间复杂度:   
            ///           T(n)=O(nlogn)
            /// 参考 优秀代码: http://zh.wikipedia.org/wiki/%E5%90%88%E4%BD%B5%E6%8E%92%E5%BA%8F
            ///               http://www.cnblogs.com/mingmingruyuedlut/archive/2011/08/18/2144984.html
            /// </summary>
            /// <param name="Array"></param>
            /// <param name="left"></param>
            /// <param name="right"></param>
            public void RecursiveMergeSort(int[] Array, int left, int right)
            {
                int middle = (left + right) / 2;
    
                if (left < right)
                {
                    //对前半部分递归拆分
                    RecursiveMergeSort(Array, left, middle);
                    //对后半部分递归拆分
                    RecursiveMergeSort(Array, middle + 1, right);
                    MergeOne(Array, left, middle, right);
                }
            }
            public void MergeOne(int[] Array, int left, int middle, int right)
            {
                int leftindex = left;
                int rightindex = middle + 1;
                //动态临时二维数组存放分割为两个小Array的数组排列顺序后的数据
                int[] merge = new int[right + 1];
                int index = 0;
                //对两个小数组合并排序
                while (leftindex <= middle && rightindex <= right)
                    merge[index++] = (Array[leftindex] - Array[rightindex]) >= 0 ? Array[rightindex++] : Array[leftindex++];
                //有一侧子数列遍历完后,将另外一侧子数列剩下的数依次放入暂存数组中(有序)
                if (leftindex <= middle)
                {
                    for (int i = leftindex; i <= middle; i++)
                        merge[index++] = Array[i];
                }
                if (rightindex <= right)
                {
                    for (int i = rightindex; i <= right; i++)
                        merge[index++] = Array[i];
                }
                //将有序的数列 写入目标数组 ,即原来把Array数组分为两个小Array数组后重新有序组合起来(覆盖原数组)
                index = 0;
                for (int i = left; i <= right; i++)
                    Array[i] = merge[index++];
            }
    
            /// <summary>
            /// 归并排序(非递归)
            ///     核心思想:(分治)
            ///           对n个数的数列每相邻两个元素排序,组成n/2个或(n+1)/2个子数组,单个的不比了直接进入下一轮。
            ///     然后对每个相邻的子数组再排序,以此类推最后得到排好序的数列 
            ///  forexample:  59 35 54 28 52 
            ///   排序And分:  35 59. 28 54. 52
            ///   排序And分:  28 35 54 59. 52
            ///        结果:  28 35 52 54 59
            /// 核心算法时间复杂度:   
            ///           T(n)=O(nlogn)
            /// </summary>
            /// <param name="Array"></param>
            public void MergeSort(int[] Array)
            {
                //index固定的数组
                int[] merge = new int[Array.Length];
                int P = 0;
                while (true)
                {
                    int index = 0;
                    //子数组元素的个数
                    int ENumb = (int)Math.Pow(2, P);
                    //一个子数组中的元素个数与数组的一半元素个数比较大小
                    //最糟糕的情况最右边的数组只有一个元素
                    if (ENumb < Array.Length)
                    {
                        while (true)
                        {
                            int TorFAndrightindex = index;
                            //最后一个子数组的第一个元素的index与数组index相比较
                            if (TorFAndrightindex <= Array.Length - 1)
                                MergeTwo(Array, merge, index, ENumb);
                            else
                                break;
                            index += 2 * ENumb;
                        }
                    }
                    else
                        break;
                    P++;
                }
            }
            public void MergeTwo(int[] Array, int[] merge, int index, int ENumb)
            {
                //换分两个子数组的index(千万不能用middle = (right + left) / 2划分)
                // 1
                int left = index;
                int middle = left + ENumb - 1;
                //(奇数时)
                //排除middleindex越界
                if (middle >= Array.Length)
                {
                    middle = index;
                }
                //同步化merge数组的index
                int mergeindex = index;
                // 2
                int right;
                int middleTwo = (index + ENumb - 1) + 1;
                right = index + ENumb + ENumb - 1;
                //排除最后一个子数组的index越界.
                if (right >= Array.Length - 1)
                {
                    right = Array.Length - 1;
                }
                //排序两个子数组并复制到merge数组
                while (left <= middle && middleTwo <= right)
                {
                    merge[mergeindex++] = Array[left] >= Array[middleTwo] ? Array[middleTwo++] : Array[left++];
                }
                //两个子数组中其中一个比较完了(Array[middleTwo++] 或Array[left++]),
                //把其中一个数组中剩下的元素复制进merge数组。
                if (left <= middle)
                {
                    //排除空元素.
                    while (left <= middle && mergeindex < merge.Length)
                        merge[mergeindex++] = Array[left++];
                }
                if (middleTwo <= right)
                {
                    while (middleTwo <= right)
                        merge[mergeindex++] = Array[middleTwo++];
                }
                //判断是否合并至最后一个子数组了
                if (right + 1 >= Array.Length)
                    Copy(Array, merge);
            }
    
            /// <summary>
            /// 自然归并排序:
            ///      对于初始给定的数组,通常存在多个长度大于1的已自然排好序的子数组段.
            /// 例如,若数组a中元素为{4,8,3,7,1,5,6,2},则自然排好序的子数组段
            /// 有{4,8},{3,7},{1,5,6},{2}.
            /// 用一次对数组a的线性扫描就足以找出所有这些排好序的子数组段.
            /// 然后将相邻的排好序的子数组段两两合并,
            /// 构成更大的排好序的子数组段({3,4,7,8},{1,2,5,6}).
            /// 继续合并相邻排好序的子数组段,直至整个数组已排好序.
            /// 核心算法时间复杂度:
            ///        T(n)=○(n);
            /// </summary>
            public void NaturalMergeSort(int[] Array)
            {
                //得到自然划分后的数组的index组(每行为一个自然子数组)
                int[,] PointsSymbol = LinearPoints(Array);
                //子数组只有一个。
                if (PointsSymbol[0, 1] == Array.Length - 1)
                    return;
                //多个(至少两个子数组)...
                else
                    //可以堆栈调用吗?
                    NaturalMerge(Array, PointsSymbol);
    
            }
            public void NaturalMerge(int[] Array, int[,] PointsSymbol)
            {
                int left;
                int right;
                int leftend;
                int rightend;
    
                mergerows = GNumberTwo(Groups);
                CopyGroups = Groups;
                //固定状态
                int[] TempArray = new int[Array.Length];
                //循环取每个自然子数组的index
                while (true)
                {
                    // int Temprow = 1;
                    //只记录合并后的子数组(”《应该为》“动态的)  
                    int[,] TempPointsSymbol = new int[mergerows, 2];
    
                    int row = 0;
                    do
                    {
                        //最重要的判断:最后(一组子数组)是否可配对
                        if (row != CopyGroups - 1)
                        { //以上条件也可以含有(& 和&&的区别)短路运算
                            //参考:http://msdn.microsoft.com/zh-cn/library/2a723cdk(VS.80).aspx
                            left = PointsSymbol[row, 0];
                            leftend = PointsSymbol[row, 1];
                            right = PointsSymbol[row + 1, 0];
                            rightend = PointsSymbol[row + 1, 1];
                            MergeThree(Array, TempArray, left, leftend, right, rightend);
                            MergePointSymbol(PointsSymbol, TempPointsSymbol, row);
                        }
                        else
                        {
                            ////默认剩下的单独一个子数组已经虚拟合并。然后Copy进TempArray。
                            int TempRow = PointsSymbol[row, 0];
                            int TempCol = PointsSymbol[row, 1];
                            while (TempRow <= TempCol)
                                TempArray[TempRow] = Array[TempRow++];
                            //TempPointSymbol完整同步
                            TempPointsSymbol[row / 2, 0] = PointsSymbol[row, 0];
                            TempPointsSymbol[row / 2, 1] = PointsSymbol[row, 1];
                            break;//重新开始新一轮循环。
                        }
                        row += 2;
                        // Temprow++;
                        //合并到只有一个子数组时结束循环
                        if (TempPointsSymbol[0, 1] == Array.Length - 1)
                            break;
                    }//判断别进入越界循环(可以进孤单循环)这里指的是PointsSymbol的子数组个数
                    while (row <= CopyGroups - 1);
                    //
                    Copy(Array, TempArray);
                    //更新子数组index,row为跳出循环的条件(最后单个子数组或下一个越界的第一个)
                    UpdatePointSymbol(PointsSymbol, TempPointsSymbol, row);
                    //改变TempPointsSymbol的行数(合并后子数组数)
                    mergerows = GNumber(mergerows);
                    CopyGroups = GNumberTwo(CopyGroups);
                    //合并到只有一个子数组时结束循环
                    if (PointsSymbol[0, 1] == Array.Length - 1)
                        break;
                }
                //输出
            }
            public int GNumber(int Value)
            {
                if (Value % 2 == 0)
                    Value /= 2;
                else
                    Value -= 1;
    
                return Value;
            }
            public int GNumberTwo(int Value)
            {
                if (Value % 2 == 0)
                    mergerows = Value / 2;
                else
                    mergerows = Value / 2 + 1;
                return mergerows;
            }
            public void MergeThree(int[] Array, int[] Temp, int left, int leftend, int right, int rightend)
            {
                //合并语句
                int index = left;
                while (left <= leftend && right <= rightend)
                    Temp[index++] = Array[left] >= Array[right] ? Array[right++] : Array[left++];
                while (left <= leftend)
                    Temp[index++] = Array[left++];
                while (right <= rightend)
                    Temp[index++] = Array[right++];
            }
            public void MergePointSymbol(int[,] PointsSymbol, int[,] TempPointsSymbol, int row)
            {
                int rowindex = row / 2;
                TempPointsSymbol[rowindex, 0] = PointsSymbol[row, 0];
                TempPointsSymbol[rowindex, 1] = PointsSymbol[row + 1, 1];
            }
            public void UpdatePointSymbol(int[,] PointsSymbol, int[,] TempPointsSymbol, int rows)
            {
                int row = 0;
                //if (mergerows % 2 == 0)
                //{
                for (; row < TempPointsSymbol.GetLength(0); row++)
                {
                    for (int col = 0; col < 2; col++)
                        PointsSymbol[row, col] = TempPointsSymbol[row, col];
                }
                //后面的清零
                for (; row < PointsSymbol.GetLength(0); row++)
                {
                    for (int col2 = 0; col2 < 2; col2++)
                        PointsSymbol[row, col2] = 0;
                }
                //}
                ////补剩下的index组,
                //else
                //{
                //    for (int row2 = 0; row2 < TempPointsSymbol.GetLength(0); row2++)
                //    {
                //        for (int col3 = 0; col3 < 2; col3++)
                //            PointsSymbol[row2, col3] = TempPointsSymbol[row2, col3];
                //    }
                //    //最后一个子数组的index只有一个。
                //    int row3 = TempPointsSymbol.GetLength(0);
                //    PointsSymbol[row3, 0] = PointsSymbol[rows, 0];
                //    PointsSymbol[row3, 1] = PointsSymbol[rows, 1];
                //    //后面的清零
                //    for (int row4 = row3 + 1; row4 < PointsSymbol.GetLength(0); row4++)
                //    {
                //        for (int col4 = 0; col4 < 2; col4++)
                //            PointsSymbol[row4, col4] = 0;
                //    }
                //}
    
            }
            public int[,] LinearPoints(int[] Array)
            {
                Groups = 1;
                int StartPoint = 0;
                int row = 0;
                int col = 0;
                //最糟糕的情况就是有Array.Length行。
                int[,] PointsSet = new int[Array.Length, 2];
                //线性扫描Array,划分数组
                //初始前index=0
                PointsSet[row, col] = 0;
                do
                {
                    //判断升序子数组最终的index开关
                    bool Judge = false;
                    //从Array第二个数判断是否要结束或者是否是升序子数组.
                    while (++StartPoint < Array.Length && Array[StartPoint] < Array[StartPoint - 1])
                    {
                        //打开第一个升序子数组结束的index开关
                        Judge = true;
                        //重新开始第二个升序子数组的前index
                        PointsSet[row, col + 1] = StartPoint - 1;
                        //计算子数组个数
                        Groups++;
                        //换行记录自然子数组的index
                        row++;
                        break;
                        //--StartPoint;
                    }
                    //升序子数组结束index
                    if (Judge)
                        PointsSet[row, col] = StartPoint;
                    //else
                    //    --StartPoint;
                } while (StartPoint < Array.Length);
                //最终index=StartPoint - 1,但是糟糕情况下还有剩余若干行为: 0,0 ...
                PointsSet[row, col + 1] = StartPoint - 1;
                //调用展示方法           
                DisplaySubarray(Array, PointsSet, Groups);
                return PointsSet;
            }
            public void DisplaySubarray(int[] Array, int[,] PointsSet, int Groups)
            {
                Console.WriteLine("Subarray is {0}:", Groups);
                //展示子数组的前后index
                for (int r = 0; r < Groups; r++)
                {
                    for (int c = 0; c < PointsSet.GetLength(1); c++)
                    {
                        Console.Write(PointsSet[r, c]);
                        if (c < PointsSet.GetLength(1) - 1)
                            Console.Write(",");
                    }
                    Console.Write("\t\t");
                }
                Console.WriteLine();
                //展示分出的子数组
                for (int v = 0; v < Groups; v++)
                {
                    int i = 1;
                    for (int r = PointsSet[v, 0]; r <= PointsSet[v, 1]; r++)
                    {
                        Console.Write(Array[r] + " ");
                        i++;
                    }
                    if (i <= 3)
                        Console.Write("\t\t");
                    else
                        Console.Write("\t");
                    if (PointsSet[v, 1] == Array.Length)
                        break;
                }
            }
    
            public void Copy(int[] Array, int[] merge)
            {
                //一部分排好序的元素替换掉原来Array中的元素
                for (int i = 0; i < Array.Length; i++)
                {
                    Array[i] = merge[i];
                }
            }
            //输出
            public override string ToString()
            {
                string temporary = string.Empty;
    
                foreach (var element in Array27)
                    temporary += element + " ";
    
                temporary += "\n";
                return temporary;
            }
        }
    }

    //结果:


  • 相关阅读:
    PHPCMS V9 导航栏当前栏目高亮
    phpcms v9栏目列表调用每一篇文章内容方法
    PHPCMS V9 为今天或几天前文章加new
    vue.js路由参数简单实例讲解------简单易懂
    vue组件知识总结
    vue.js 利用组件之间通讯,写一个弹出框例子
    vue.js组件之间通讯--父组件调用子组件的一些方法,子组件暴露一些方法,让父组件调用
    vue.js组件之间的通讯-----父亲向儿子传递数据,儿子接收父亲的数据
    vue.js通讯----父亲拿儿子的数据
    git常见操作---由简入深
  • 原文地址:https://www.cnblogs.com/wjshan0808/p/3008950.html
Copyright © 2011-2022 走看看