排序方法的总结

h啊哈哈哈哈,开心,终于有时间,来搞我们的各种排序算法了

不懂算法的程序员,都不是合格的程序员;

首先要明白两个基本概念;

  1.时间复杂度和空间复杂度;

http://blog.csdn.net/booirror/article/details/7707551/

   2.还有稳定与不稳定;

首先,你要觉得很神奇:就一个数组+for循环+if+else,就实现我们这么多的排序;

这里,我们要考虑到一个稳定性的考虑;就是当两个数相等的时候;如:冒泡排序,当两个数一样的时候,我们就没有必要交换它(当然,你也可以交换它,这样就不是稳定了),这样就是稳定的

看看我们的快速排序呢是否是稳定的呢;

常见的算法:

1.冒泡排序;

2.选择排序;

3.快速排序;

     在做快速排序的算法总结之前;我们先做这样的一道栗子;将数组分成两部分;一部分比key大,一部分比key小;

然后做法,目前有三种;方式一和方式二雷同;方式三和前面两种实现方式完全不同,我具体的开代码的实现;

方式一是存的value,我们也可以存index,大同小异,我这里只写一种;

       /// <summary>
        /// 这个是利用一次遍历,一个数,要么比key大,要么比key小;
        /// 我们分别申明两个数组;min 和 max 来存储;
        /// 然后将min 和max 进行合并;
        /// </summary>
        /// <param name="arr"></param>
        public static void TestSplitArr(int [] arr)
        {
            int len = arr.Length;
            int[] min = new int[len]; //只能用最大值的方式进行容纳;
            int[] max = new int[len];
            int key = arr[0]; //默认取第一位吧;
            int minIndex=0, maxIndex=0;
            for(int i = 0; i < len; i++)
            {
                if (arr[i] < key)
                {
                    min[minIndex++] = arr[i];
                }
                else
                {
                    max[maxIndex++] = arr[i]; //等于当成max 来处理;
                }
            }

            //遍历完之后,就会得到我们的;想要的结果;newArr=min+max;
            int index = 0;
            for(int i = 0; i < minIndex; i++)
            {
                arr[index++] = min[i];
            }

            for (int i = 0; i < maxIndex; i++)
            {
                arr[index++] = max[i];
            }

            //这样,就组合完毕啦滴啊;

        }

然后我们看方式二;方式二的实现,是我们快速排序的基础;

   /// <summary>
        /// 这样的话,我们就需要我么的中间min 和 max 了;这样就节约了我们的内存;
        /// </summary>
        /// <param name="arr"></param>
        public static void TestSplitArr2(int[] arr)
        {

            int len = arr.Length;
            int low = 0;
            int high = len - 1;
            int key = arr[0]; //暂定默认为第一位;
            while (true)
            {
                //从左边开始
                while (arr[high]>key && low < high)
                {
                    high--;
                }
               //从右边开始;
               while(arr[low]<key && low < high)
                {
                    low++;
                }
                //找到i 和 j 之后,我们开始交换;
                if (low >= high)
                    return;  //退出我们的查找;
                //进行交换;
                int temp = arr[low];
                arr[low] = arr[high];
                arr[high] = temp;


            }
        }

从上面的写法中,我们可以总结一些东西出来;当我们需要进行折半查找的时候;

如果len=5(奇数) loopTimes=len/2=2(向下取整)

如果len=4(偶数) loopTimest=len/2=2(刚好等于2)

这样我们的循环次数(不管奇数偶数),循环的次数都是2次;

如果恰好为偶数,那么根据小标来遍历,刚好遍历完;

如果是是奇数,那么,我们就会少遍历一次;

如果所示:

这样不管是奇数个数的数组,还是偶数个数的数组,我们都有解决方法;

下面我就要上神奇的代码了;

        /// <summary>
        /// 
        /// </summary>
        public static void TestPointer()
        {
            //var arr = new[] {1,2,3,4,5,6}; //偶数
            var arr = new[] { 1, 2, 3, 4, 5}; //奇数
            int len = arr.Length;

            int high = len - 1 + 1;
            int low = 0 - 1;
            while (low<high)
            {
                while (--high > low)
                {
                    Console.WriteLine("high address output:"+arr[high]);
                    break;
                }
                while (++low < high)
                {
                    Console.WriteLine("low address output:" + arr[low]);
                    break;
                }
            }
            //这个操作的特点四,在进行比较的时候,先进行一次自鞥,或 自减;
            //当是 偶数的时候, 关键点在 low=2 high=3; 这样的我们的遍历刚好结束;在进来遍历的时候, 先自减一次;--high ==2   这个时候 不满足 high>low 不进行数组输出;
            //当是 奇数的时候, 关键点在 low=1 high=3;  这样的我们的遍历刚好结束;在进来遍历的时候  先自减一次; --high ==2; 2>1 可以输出我们的中间数(3),下一步;先自加 ++low   low=2 high=2 不满足我们的添加,不执行后面的代码;
            //你可以理解成将我们的中间数,让给了 high 进行输出;
            //这段是很神奇的;


        }

这里就涉及一个循环中添加检查的先后顺序的问题; 

 var arr = new[] { 1, 5, 3, 4, 57, 5, 5, 53 };

这段数组,很神奇;

然后,再来实现,我们的快速排序了三;现在,我将上面的方法改成通用的,就可以实现我们递归调用;

        /// <summary>
        /// 这样我们一次交换就算完成了;
        /// </summary>
        /// <param name="arr"></param>
        /// <param name="low"></param>
        /// <param name="high"></param>
        public static int QuickSortUnit(int [] arr ,int low,int high)
        {
                while (low < high)
                {
                    int key = arr[low];
                    //从high=>low
                    while(arr[high]>=key && low < high)
                    {
                        high--;
                    }

                    while(arr[low]<key && low < high)
                    {
                        low++;
                    }
                    int temp = arr[low];
                    arr[low]=arr[high];
                    arr[high] = temp;
                    
                }
                return high;
            
        }

        /// <summary>
        /// 递归调用;
        /// </summary>
        /// <param name="arr"></param>
        /// <param name="low"></param>
        /// <param name="high"></param>
        public static void Sort(int [] arr,int low,int high)
        {
            if (low >= high)
                return;
            int index=QuickSortUnit(arr, low, arr.Length - 1);  //完成第一次排序将问题,分成了两个部分;小于key 和 大于的key的部分;一份为2;
            //然后对不同的部分进行排序;
            Sort(arr,low,index-1);//左边单元进行排序
            Sort(arr,index+1,high);//右边单元进行排序
        }

        /// <summary>
        /// 测试
        /// </summary>
        public static void Test()
        {
            var arr = new int[] {3,4,23,2,333,5,6, };
            int low = 0;
            int high = arr.Length - 1;
            Sort(arr,low,high);

            foreach (var item in arr)
            {
                Console.WriteLine(item);
            }

        }

 然后,我们尝试从中间取值为key 进行排序;

这里面,还有一个非常重要的,需要靠的就是,稳定性,当遇到相等的值的时候,如何进行交换呢;????

这个考虑的问题还是比较多的;

1.如何去中间的值?

2.算法是否稳定,当遇到相等的值,我们应该如何处理? 然后又如何交换呢;

4.插入排序;

5.希尔排序;

6.并归排序;

7.堆排序;

8.计数排序;

9.桶排序;

10基数排序;

原文地址:https://www.cnblogs.com/mc67/p/7614965.html