快速排序

来源:互联网 发布:linux vi 移动到行尾 编辑:程序博客网 时间:2024/04/30 04:18

     今天上午开始看的快速排序,原理百度出来的:

     

设要排序的数组是A[0]……A[N-1],首先任意选取一个数据(通常选用数组的第一个数)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。值得注意的是,快速排序不是一种稳定的排序算法,也就是说,多个相同的值的相对位置也许会在算法结束时产生变动。
一趟快速排序的算法是:

1)设置两个变量i、j,排序开始的时候:i=0,j=N-1;
2)以第一个数组元素作为关键数据,赋值给key,即key=A[0];
3)从j开始向前搜索,即由后开始向前搜索(j--),找到第一个小于key的值A[j],将A[j]和A[i]互换;
4)从i开始向后搜索,即由前开始向后搜索(i++),找到第一个大于key的A[i],将A[i]和A[j]互换;
5)重复第3、4步,直到i=j; (3,4步中,没找到符合条件的值,即3中A[j]不小于key,4中A[i]不大于key的时候改变j、i的值,使得j=j-1,i=i+1,直至找到为止。找到符合条件的值,进行交换的时候i, j指针位置不变。另外,i==j这一过程一定正好是i+或j-完成的时候,此时令循环结束)。
然后自己写的第一遍排序的代码:
<pre name="code" class="java">package testjson;import org.junit.Test;public class Quicksort {private int i;private int j;int t = 0;int[] tie = new int[5];public int qp(int[] score, int i, int j) {int temp;int key;int n = j;int m = i;key = score[i];for (j = n; j > i; j--) {if (score[j] < key) {temp = score[j];score[j] = score[i];score[i] = temp;for (i = m; i < j; i++) {if (score[i] > key) {temp = score[i];score[i] = score[j];score[j] = temp;break;}}}}System.out.println("排序完成后的结果:");for (i = 0; i < score.length; i++) {System.out.print(score[i] + ",");}return j;}@Testpublic void test() {int[] score = { 3, 5, 9, 2, 1, 8, 4, 6 };i = 0;j = score.length - 1;qp(score, i, j);}}
全部排序完成需要用到递归算法,自己写的递归感觉很正确
package testjson;import org.junit.Test;public class Quicksort {private int i;private int j;int t = 0;int[] tie = new int[5];public int qp(int[] score, int i, int j) {int temp;int key;int n = j;int m = i;key = score[i];for (j = n; j > i; j--) {if (score[j] < key) {temp = score[j];score[j] = score[i];score[i] = temp;for (i = m; i < j; i++) {if (score[i] > key) {temp = score[i];score[i] = score[j];score[j] = temp;break;}}}}qp(score, j + 1, score.length - 1);qp(score, i, j - 1);System.out.println("排序完成后的结果:");for (i = 0; i < score.length; i++) {System.out.print(score[i] + ",");}return j;}@Testpublic void test() {int[] score = { 3, 5, 9, 2, 1, 8, 4, 6 };i = 0;j = score.length - 1;qp(score, i, j);}}
调试了几次逻辑走的不对,ij在第二次快排的时候最后值都不同,最后看了别人的分析才知道用到不只是递归,递归只是解决问题的方式,用的分治法,分治法的大致思想是,把问题分为小问题,用递归或者其他方式解决小问题,再把小问题合起来为问题本身
以下是别人的分析:

它的一般的算法设计模式如下:

Divide-and-Conquer(P)

1. if |P|≤n0

2. then return(ADHOC(P))

3. 将P分解为较小的子问题 P1 ,P2 ,…,Pk

4. for i←1 to k

5. do yi ← Divide-and-Conquer(Pi) △ 递归解决Pi

6. T ← MERGE(y1,y2,…,yk) △ 合并子问题

7. return(T)

其中|P|表示问题P的规模;n0为一阈值,表示当问题P的规模不超过n0时,问题已容易直接解出,不必再继续分解。ADHOC(P)是该分治法中的基本子算法,用于直接解小规模的问题P。因此,当P的规模不超过n0时直接用算法ADHOC(P)求解。算法MERGE(y1,y2,…,yk)是该分治法中的合并子算法,用于将P的子问题P1 ,P2 ,…,Pk的相应的解y1,y2,…,yk合并为P的解。

所以我的问题出在,我并没有把问题明显的细分,我只用到递归,而且递归用的不对,关键的代码是:

int middle = getMiddle(list, low, high);  //将list数组进行一分为二     
 
               _quickSort(list, low, middle - 1);        //对低字表进行递归排序     
 
              _quickSort(list, middle + 1, high);       //对高字表进行递归排序   

这么看我的问题出在我没有划分明确,逻辑思路有点混乱,还好自己已经测试完成明白了整体的流程,完全画了流程图
下边附带一下完整的代码,此代码为网上查找别人的代码改编,改日再自己写代码:
package testjson;import org.junit.Test;//网上找的实例public class Zquicksort {       int a[] = {3,5,9,2,1,8,4,6};  @Test  public void quickSort(){        quick(a);        for(int i=0;i<a.length;i++)           System.out.print(a[i]+",");    }    public int getMiddle(int[] list, int low, int high) {                   int tmp = list[low];    //数组的第一个作为中轴                   while (low < high) {                       while (low < high && list[high] >= tmp) {                           high--;                       }                       list[low] = list[high];   //比中轴小的记录移到低端                       while (low < high && list[low] <= tmp) {                           low++;                       }                       list[high] = list[low];   //比中轴大的记录移到高端                   }                  list[low] = tmp;              //中轴记录到尾                //System.out.println(tmp+","+low);           System.out.println("排序完成后的结果:"+low);   for(int p=0;p<a.length;p++){       System.out.print(a[p]+",");       }              return low;                   //返回中轴的位置               }      public void _quickSort(int[] list, int low, int high) {                   if (low < high) {                      int middle = getMiddle(list, low, high);  //将list数组进行一分为二                                   _quickSort(list, low, middle - 1);        //对低字表进行递归排序                               _quickSort(list, middle + 1, high);       //对高字表进行递归排序                   }               }     public void quick(int[] a2) {                   if (a2.length > 0) {    //查看数组是否为空                       _quickSort(a2, 0, a2.length - 1);               }              }     }    


回头看自己写的代码,我用的是FOR循环,它写的是while循环,但是我的写法是错的,正确的写法改怎么写呢。自己没看出来。。回去问了问对象,解决了,是我最后没有break所以会再次j--然后再跳出循环,这个涉及到for循环本身的执行顺序:先执行j=7代入,然后第一遍循环完成之后执行j--,然后再次判断,如果成立继续执行,不成立则跳出。我再后边语句加了break就会直接跳出for循环,不至于进行再次判断。下边是别人说的百度的:
for(a;b;c)执行顺序先执行a在判断b是否为真,若为真执行循环体,执行c然后再次判断b是否为真,若为真执行循环体执行c。。。直到b为假,跳出循环
一下是改好的代码:
package testjson;import org.junit.Test;public class Quicksort {int[] score = { 3, 5, 9, 2, 1, 8, 4, 6 };public int qp(int[] score, int i, int j) {int temp;int key;int n = j;int m = i;key = score[i];for (j = n; j > i; j--) {if (score[j] < key) {temp = score[j];score[j] = score[i];score[i] = temp;for (i = m; i < j; i++) {if (score[i] > key) {temp = score[i];score[i] = score[j];score[j] = temp;break;}}}if(i==j){break;}}System.out.println("排序完成后的结果:"+j);for (i = 0; i < score.length; i++) {System.out.print(score[i] + ",");}return j;}public void quick(int[] list, int low, int high) {if (low < high) {                   int middle = qp(list, low, high);  //将list数组进行一分为二                            quick(list, low, middle - 1);        //对低字表进行递归排序                         quick(list, middle + 1, high);       //对高字表进行递归排序              }     }@Testpublic void test() {quick(score,0,score.length-1);}}


快速排序到此技术,过两天过来改改语言表达。
本来不打算看非递归排序,感觉不怎么会用到,但是看了下别人写的代码用到栈了,这个得学啊,先留下网址,等以后看到栈的时候再看,先记录下
http://blog.csdn.net/yunzhongguwu005/article/details/9455991
http://www.douban.com/note/234724751/


1 0
原创粉丝点击