今天继续我们的快速排序算法
哎,网上大多数的讲解基本上都是你抄我,我抄你的,没有一个完整有道理的讲解滴呀;今天让哥来给你讲个明白;
ps:如果你对快速排序一点都不了解,那么。。你还是先不要看了,先去看看其他人的........(-_-)
核心:“找到元素本应该所在的位置”- 任何一个排好顺序的数组中的任何一个数字(x)都应该有这样的规律:x它大于任何一个左边的数,小于任何一个任何一个右边的数,(ps,我这里说的是从小到大的顺序)
乱顺实例: 2 5 1 3 8
那么本应该的顺序是:1 2 3 5 8,哎,顺便吐槽一哈,网上的答案真的是前篇一律,都没有一个有自己见解的,我艹;然后,参见红色字体的内容;
在我们的乱序中,我们先找到2 应该锁在的位置: 也就是数组下标1,
先从右边找,找到第一个比x小的数,然后
这样在第一次循环号,我们的额乱序数组,就被分成了左右连个区域的呀,然后接着调用递归分区最最大值的结果滴呀;
代码:
一些较为有用额注释:
//再一次的总结我们的各种基本额选择排序算法;
//今天继续我们的各种算法滴呀;
//其中一部分的数据比另外一部的数据小弟呀;
//强烈建议,在比较的时候,不要使用的left 和right 两个变量;
//用low 和ghi 比较合适,这样不用弄晕滴呀;
//不用的比喻方式,有的人叫他填坑方法,有的人的叫它归为方法
//去找到属于它的位置;
//它只是在描述过程,并没有清楚的讲述清楚原理滴哎呀;
//找到基准数,本应该锁锁在的位置 这个正确的说法,叫做找到数据本应该说在的位置;
public static int GetSupposedPosition(int [] s, int l, int r) //返回调整后基准数的位置 { int i = l, j = r; int x = s[l]; //s[l]即s[i]就是第一个坑 while (i < j) { // 从右向左找小于x的数来填s[i] while (i < j && s[j] >= x) j--; if (i < j) { s[i] = s[j]; //将s[j]填到s[i]中,s[j]就形成了一个新的坑 i++; } // 从左向右找大于或等于x的数来填s[j] while (i < j && s[i] < x) i++; if (i < j) { s[j] = s[i]; //将s[i]填到s[j]中,s[i]就形成了一个新的坑 j--; } } //退出时,i等于j。将x填到这个坑中。 s[i] = x; return i; //这样就找到了我们s[i]所在的位置; }
最后上我们完整的代码;
public static void FuckQuickSort(int [] arr,int l,int r) { if (l < r) { int i = l, j = r,x = arr[l]; while (i < j) { while(i<j && arr[j] >= x) { j--; //这个就是继续寻找的意思滴呀;,比我们基准数大的,我们就不动它 } if (i < j) { arr[i] = arr[j]; i++; } while(i<j && arr[i] < x) { i++; //比我们基准数小的,我们就不动它,让它留在原地; } if (i < j) { arr[j] = arr[i]; j--; } }//当退出循环的时候; arr[i] = x; //第一次排序,就是为了找这个中间值,比中间值大的都在我们的额右边,比中间值小的数据都在我们左边; //然后再利用我们的递归,分别对左右两边的额数据,进行各种排序滴呀; //这样额效果还是不错滴呀; FuckQuickSort(arr,l,i-1); //右边的 FuckQuickSort(arr,l+1,r); //左边的 } }
效果是很不错的滴呀;
然后就是我们快速排序到的各种优化滴呀;
方式一:
//不管选择哪个方向,都要把我们的基本的算法搞好滴呀; //继续我们的 快速排序的各种优化; //算法若都能分成两个等长的子序列时,那么分治算法效率会达到最大 //最理想的方法是,选择的基准恰好能把待排序序列分成两个等长的子序列 public static void QsortCommon(int [] arr,int low,int high) { if (low >= high) return; //递归的出口; int index = Partition(arr,low,high); QsortCommon(arr,low,index-1); //右边进行排序 QsortCommon(arr,index+1,high);//左边的进行排序; } public static int Partition(int [] arr,int low,int high) { int first = low; int last = high; int key = arr[first];//选择我们的第一个元素最为我们的基准元素滴啊; while (first < last) { while(first<last && arr[last] >= key) { last--; } //找到小于基准数的值;并且移动到左边 arr[first] = arr[last]; while(first<last && arr[first] <= key) { first++; } //找到比基准值大的数据,并将其移动到我们的 右边; arr[last] = arr[first]; } //最后得到分区效果,也就是找到我们的基准数,本来应该所在的位置; arr[last] = key; return last;//返回基准值所在下标; }
选取数组中的任意元素进行:
//思想:取待排序列中任意一个元素作为基准元。 //随机基准元素,将确定好的基准元素与第一个元素讲好;//无返回值; public static void PartitionRandom(int [] arr,int low,int high) { Random rd = new Random(); int randomIndex = rd.Next()%(high-low)+low; //数组中的随机一个数据 与我们的基准数进行交换; int temp = arr[0]; arr[0] = arr[randomIndex]; arr[randomIndex] = temp; }