码迷,mamicode.com
首页 > 其他好文 > 详细

初探快排

时间:2015-11-27 15:02:00      阅读:229      评论:0      收藏:0      [点我收藏+]

标签:

学了数据结构,实现下快排,

public void QuickSort1(float[] seq,int low,int hight)
{
int i = low;//记录最左值索引
int j = hight;//记录最右值索引
float temp = seq[low];//记录比较值(此处是最左值)
while (low < hight)//每轮比较
{
while (low < hight && temp >= seq[hight])
{
hight--;
}
seq[low] = seq[hight];//将右边低于比较值的放在前一个被记录的值,seq[low]值已经被记录(最先前的seq[low]值被temp记录),小于比较值的放在左边,右边迭代比出的是小于比较值的,所以先从右边开始,若要先从左边开始,选择的比较值应该是右边的最后一个
low++;//seq[low]此时已被右边的值代替,应该递增一下
while (low < hight && temp <= seq[low])
{
low++;
}
seq[hight] = seq[low];//将左边高于比较值的放在被记录的那个值上面,
hight--;//seq[hight]此时被左边的值代替,递减一下
}

seq[low]=tmp;//将比较值放在中间
if (i < low - 1)//对前半部分继续快排
{
QuickSort1(seq, i, low - 1);
}
if (j > low + 1)//对后半部分继续快排
{
QuickSort1(seq, low + 1, j);
}
}
public void QuickSort2(float []seq,int low,int hight)
{
float temp = seq[low];
int i= low;
int j= hight;
while(low<hight)
{
while (low < hight && temp >= seq[low])
{
low++;
}
while (low < hight && temp <= seq[hight])
{
hight--;
}

if(low<hight){
float middle = seq[low];
seq[low] = seq[hight];
seq[hight] = middle;

}
}

if(i<hight)
{

float middle =seq[i];

seq[i]=seq[height];

seq[height]=middle;

}
if (i < low - 1)
{
QuickSort2(seq, i, low - 1);
}
if (j > low + 1)
{
QuickSort2(seq, j, low + 1);
}
}

}

个人刚接触快排时,感觉QuickSort2易于接受些,QuickSort1相对比较不好理解,但是两个原理是一样的,先讲下我理解的快排思路,降序和升序是一样的,以升序为例,在要排序的数组选取一个比较值,比比较值小的放左边,比比较值大的放右边,降序刚好相反,通常都是选取第一个为比较值,选第一个为比较值就必须先从右边开始递减比较大小,因为记录的是左边的第一个值,满足比比较值小的右边的值必须放在左边,而恰好左边第一个值即比较值已经被记录了,可以被替代掉,如果从左边开始递增比较大小,那么满足比比较值大的应该放在右边,而右边还没有被记录的值,右边的某个值就会被覆盖掉,所以先从右边开始递减与比较值比较大小,一轮比较过后,比比较值小的放在左边,比比较值大的放在右边,比较值放在中间,再从分成的这两部分再进行一轮比较,不断分化比较,直到进行一轮比较的只有两个数或三个数时,才算最后一轮比较,比较完,就不再进行比较,运用了分治和递归的思想

先讲讲QuickSort1,先记录要比较的数组的范围界限,i=low;j=hight;它除了作为迭代数,还要作为递归的判断条件,然后从右边开始迭代,在满足low<hight的情况下进行一轮比较,右边迭代到满足条件的右边值时,将右边值记录到左边的已经被记录的值上,再进行左边迭代到满足条件的左边值时,再将左边值记录到右边已经被记录的值上(这是上一轮右边迭代记录的值),不断迭代,直到low>=hight表示一轮比较结束,再将temp即比较值放在中间,即seq[low],再将i与low-1比较,j与low+1比,看是否最后一轮比较是否完毕,完毕即i>=low-1,j<=low+1不进行递归函数,不进行新的一轮比较,快排完成,否则就不断递归,不断进行新的一轮比较

QuickSort2,大体思路也是QuickSort1,不过它是等左边迭代和右边迭代完成之后,再进行记录交换,这样先进行右边迭代和先进行左边迭代没什么区别,也没有限制非要先从右边开始迭代,它们交换两边值的方式不同,QuickSort1利用了比较值所占的两个内存,利用其中一个内存来储存要记录的值,从而不用创建临时变量,首先将右边的值用比较值来储存,此时右边的值被记录又可以用来记录左边的值,相当于一个首位为空的链表(每个元素的位置不是挨着的)前移了一位,这是QuickSort1的交换两边的值的方式,而QuickSort2就简单暴力多了,直接两边值交换,没有利用比较值所占的两个内存(temp和seq[low]),哪种写法比较好?我觉得具体情况具体分析,QuickSort1的优点是不需要创建临时变量,缺点是若选定一个比较值,必须先从固定的一边去迭代。QuickSort2就是可以两边都可以先迭代,但是要创建临时变量

比较值的选取对于QuickSort2没什么影响,(指代码不需要改)对于QuickSort1有影响,若是选择最右边一个为比较值,就先左迭代。比较值选中间的话,左右迭代顺序就无所谓了,选偏左的值作为比较值,就先从右边迭代,它比比较值小的的值放在左边,左边的比较值被记录,可以存放,就不会被覆盖,同理选偏右的值作为比较值,就从左边迭代。这个例子是升序排列,降序也是同理,但是是相反的。

再讲讲时间复杂度,取决于比较值的大小,若刚好是序列中(数组)的中间值,那么每轮比较过后的序列(数组)都分成等长的两个子序列,这是最佳情况,每轮比较过花的是n的时间复杂度,而只需要比较log2的n次方轮,所以最佳时间复杂度为n*log2 n;最坏的情况是每轮比较过后的序列分成一个空序列,长度为原来序列-1的子序列,比较值是序列中的最大值或最小值,只是把比较值分离出去了,要比较n轮才会排序完成,所以最坏时间复杂度为n*n,一般来说,序列中的数分布比较均匀,平均复杂度仍为n*log2 n;

比较值的选取决定着时间复杂度,对于比较值的选取网上有更深入的讨论,在此推荐几种快排变种,比如

变种随机化快排

平衡快排(Balanced Quicksort)

外部快排(External Quicksort):

三路基数快排(Three-way Radix Quicksort,也称作Multikey Quicksort、Multi-key Quicksort):

初探快排

标签:

原文地址:http://www.cnblogs.com/DragonDXDXD/p/5000550.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!