zoukankan      html  css  js  c++  java
  • 排序方法的总结

    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基数排序;

  • 相关阅读:
    九度-题目1197:奇偶校验
    九度-题目1073:杨辉三角形
    九度-题目1072:有多少不同的面值组合?
    同步异步,阻塞非阻塞
    注解方式配置bean
    监听器
    自定义系统初始化器
    构建流
    数值流
    流的使用
  • 原文地址:https://www.cnblogs.com/mc67/p/7614965.html
Copyright © 2011-2022 走看看