package Exp5; import java.util.Random; import tools.TimeTest; public class Sort{ /** * variables * */ final static int[] a={44,77,55,99,66,33,22,88,77}; final static String[][] SORTCOMPARE={ {"排序方法","最好时间复杂度","平均时间复杂度","最坏时间复杂度","空间复杂度","稳定性 "}, {"直接插入","O(n) ","O(n*n) ","O(n*n) ","O(1) "," 稳定 "}, {"希尔排序","``` ","O(n(1.3)) ","``` ","O(1) "," 不稳定 "}, {"直接选择","O(n*n) ","O(n*n) ","O(n*n) ","O(1) "," 稳定 "}, {"堆排序 ","O(nlbn) ","O(nlbn) ","O(nlbn) ","O(1) "," 不稳定 "}, {"冒泡排序","O(n) ","O(n*n) ","O(n*n) ","O(1) "," 稳定 "}, {"快速排序","O(nlbn) ","O(nlbn) ","O(n*n) ","O(lbn) "," 不稳定 "}, {"归并排序","O(nlbn) ","O(nlbn) ","O(nlbn) ","O(n) "," 稳定 "}, {"基数排序","O(n*m) ","O(n*m) ","O(n*m) ","O(n) "," 稳定 "} }; /** * main */ public static void main(String[] args) { /**问题1--数组内存共享 * final static int[] a={44,77,55,99,66,33,22,88,77}; * int[] b=a; * 则a与b将会共享一块内存, * 这个时候,无论你的a是否是static final修饰的, * 只要a改变,b就会改变, * 只要b改变,a就会改变, * 这样做可能是java为了提高内存的利用效率,而忽略了final关键字, * 请查实!! * 既然如此,只好写个copy方法来解决这个问题 * */ /** * 问题2:mergeSort存在异常 * 解决:书上的代码是对的,附带的代码是错的... * */ /** * 问题三 * 改进堆排序和归并排序这两种方法,让他们更快! * */ /** * 各种排序方法的比较 * */ System.out.println("各种排序方法的比较"); print2(SORTCOMPARE);//输出各种排序方法的比较 /** * 正确性验证 * */ System.out.println("正确性验证"); int[] temp=new int[a.length]; copy(temp,a); System.out.println("insertSort"); print(temp); print(insertSort(temp)); copy(temp,a);//用自己写的方法,将两个数组分配到不同的内存中区,从而互不干扰 System.out.println("insertSortPro"); print(temp); print(insertSortPro(temp)); copy(temp,a); System.out.println("simChoseSort"); print(temp); print(simChoseSort(temp)); copy(temp,a); System.out.println("selectSortPro"); print(temp); print(selectSortPro(temp)); copy(temp,a); System.out.println("heapSort"); print(temp); heapSort(temp ); print(temp); copy(temp,a); System.out.println("bubbleSort"); print(temp); bullboSort(temp); print(temp); copy(temp,a); System.out.println("bubbleSortPro"); print(temp); print(bubbleSortPro(temp)); copy(temp,a); System.out.println("quickSortPro"); print(temp); quickSortPro(temp,0,temp.length-1); print(temp); copy(temp,a); System.out.println("shellSort"); print(temp); int[] b={6,3,1}; shellSort(temp,b,3); print(temp); copy(temp,a); System.out.println("mergeSort"); print(temp); try{ mergeSort(temp); } catch(Exception ee){ ee.printStackTrace(); } print(temp); copy(temp,a); System.out.println("radixSort"); print(temp); try { radixSort(temp,3,10); } catch (Exception e) { e.printStackTrace(); } print(temp); /** * 用TimeTest类测试各种方法的运行时间 * */ System.out.println("用TimeTest类测试各种方法的运行时间"); int len=100000; int[] kk=new int[len]; TimeTest timeTest=new TimeTest(); Random random=new Random(); for(int i=0;i<kk.length;i++){ kk[i]=random.nextInt(len); } //我讨厌这些东西...... int[] kk1=new int[len]; int[] kk2=new int[len]; int[] kk3=new int[len]; int[] kk4=new int[len]; int[] kk5=new int[len]; int[] kk6=new int[len]; int[] kk7=new int[len]; int[] kk8=new int[len]; int[] kk9=new int[len]; int[] kk0=new int[len]; int[] kka=new int[len]; int[] kkb=new int[len]; int[] kkc=new int[len]; int[] kkd=new int[len]; int[] kke=new int[len]; int[] kkf=new int[len]; copy(kk1,kk); copy(kk2,kk); copy(kk3,kk); copy(kk4,kk); copy(kk5,kk); copy(kk6,kk); copy(kk7,kk); copy(kk8,kk); copy(kk9,kk); copy(kk0,kk); copy(kka,kk); copy(kkb,kk); copy(kkc,kk); copy(kkd,kk); copy(kke,kk); copy(kkf,kk); /** * 或许,我该写个框架来处理这些无聊而充实的重复 * */ { print(kk1,10,10,"排序前"); timeTest.start(1, "insertSort--插入排序"); insertSort(kk1); timeTest.stop(); print(kk1,10,10,"排序后"); } { print(kk2,10,10,"排序前"); timeTest.start(1, "insertSortPro--插入排序,我的版本"); insertSortPro(kk2); timeTest.stop(); print(kk2,10,10,"排序后"); } { print(kk3,10,10,"排序前"); timeTest.start(1, "selectSortPro--选择排序,我的版本"); selectSortPro(kk3); timeTest.stop(); print(kk3,10,10,"排序后"); } { print(kk5,10,10,"排序前"); timeTest.start(1, "quickSortPro--快速排序,我的版本"); quickSortPro(kk5,0,len-1); timeTest.stop(); print(kk5,10,10,"排序后"); } { print(kk6,10,10,"排序前"); timeTest.start(1, "heapSort--堆排序"); heapSort(kk6); timeTest.stop(); print(kk6,10,10,"排序后"); } { int[] d={4096,2048,1024,512,256,128,64,32,16,8,4,2,1}; print(kkc,10,10,"排序前"); timeTest.start(1, "shellSort--希尔排序"); shellSort(kkc,d,d.length); timeTest.stop(); print(kkc,10,10,"排序后"); } { print(kkd,10,10,"排序前"); timeTest.start(1, "radixSort--基数排序"); try { radixSort(kkd,5,10); } catch (Exception e) { e.printStackTrace(); } timeTest.stop(); print(kkd,10,10,"排序后"); } { print(kke,10,10,"排序前"); timeTest.start(1, "simChoseSort--选择排序"); simChoseSort(kke); timeTest.stop(); print(kke,10,10,"排序后"); } { print(kkf,10,10,"排序前"); try{ timeTest.start(1, "mergeSort--归并排序"); mergeSort(kkf); timeTest.stop(); } catch(Exception e){ e.printStackTrace(); } print(kkf,10,10,"排序后"); } { print(kk4,10,10,"排序前"); timeTest.start(1, "bubbleSortPro--冒泡排序,我的版本"); bubbleSortPro(kk4); timeTest.stop(); print(kk4,10,10,"排序后"); } { print(kk7,10,10,"排序前"); timeTest.start(1, "bubbleSort--冒泡排序"); bullboSort(kk7); timeTest.stop(); print(kk7,10,10,"排序后"); } /**测试结果 * 对于int kk=new int[10000]; * `heapSort--堆排序` spends `0.047` seconds * `mergeSort--归并排序` spends `0.047` seconds * * 是冒泡排序法[表现最差]107.015s的 * 2276.9148936170212765957446808511倍! * 次优的是shellSort,0.172s完成 * `radixSort--基数排序` spends `0.813` seconds * quickSortPro'11.563's * insertSort`15.0` seconds * selectSortPro`25.719` seconds * insertSortPro`36.968` seconds//我的改进...好失败... * simChoseSort--选择排序` spends `64.765` seconds * bubbleSortPro`105.203` seconds//才快2s * * 方法越简单,速度越慢... * 所有考试才考冒泡, * 如果考堆和归并排序,不知道要死多少人.:) * 下面我要改进堆排序和归并排序这两种方法,让他们更快! * */ } /** * print(int[] a) * 打印输出 * */ public static void print(int[] a){ for(int i=0;i<a.length;i++){ System.out.print(a[i]+"/t"); } System.out.println(); } /** * print(int[] a,int heads,int last,String hint) * 打印输出 * */ public static void print(int[] a,int heads,int last,String hint){ System.out.println("/t"+hint); if(heads>=a.length||last>=a.length){ print(a); return; } System.out.println("The head `"+heads+"`elements"); for(int i=0;i<heads;i++){ System.out.print(a[i]+"/t"); } System.out.println("/t"); System.out.println("The last `"+last+"`elements"); for(int i=a.length-last;i<a.length;i++){ System.out.print(a[i]+"/t"); } System.out.println("/t"); System.out.println(""); } /** * print2(String[][] aa) * 打印输出 * */ public static void print2(String[][] aa){ for(int i=0;i<aa.length;i++){ for(int k=0;k<aa[i].length;k++){ System.out.print("/t" +aa[i][k]); } System.out.println(); } } /** * copy(int[] a1,int[] a2) * 把a2拷贝到a1中去 * */ public static void copy(int[] a1,int[] a2){ if(a1.length!=a2.length){ return ; } for(int i=0;i<a1.length;i++){ a1[i]=a2[i]; } } /** * 插入排序 * insertSort(int[] a2) * 直接插入排序 * */ public static int[] insertSort(int[] a2){ int n=a2.length; int i=0,j=0,temp; for( i=0;i<n-1;i++){ temp=a2[i+1]; j=i; while(j>-1&&temp<=a2[j]){ a2[j+1]=a2[j]; j--; } a2[j+1]=temp; } return a2; } /** * 直接插入排序 * insertSortPro(int[] a) * @author Allchin * */ public static int[] insertSortPro(int[] a){ int i=1, c=a.length,//a2.length k=0,// temp=0, m=i; for(i=1;i<c;i++){//从数组1循环到数组结束 for(k=0;k<i;k++){//循环检索已经排序的部分--就是当前元素前面的元素 if(a[k]>a[i]){//如果已排序的部分有a[k]>当前的元素 temp=a[i];//将 当前数 保存到temp for(m=i;m>k;m--){//被插数位置后面的元素想后移动一位,到当前数位置为止 a[m]=a[m-1]; } a[k]=temp;//被插数的位置写入当前数 } /* //如果已经排序的数据部分没有比当前元素大的,就什么都不干,这样就保证了数组的稳定性 //如果按照我的排序过程中的比较规则(仅当--已排序的部分有a[k]>当前的元素,才执行移动操作) //就能够保证这个直接插入排序算法的稳定性! * */ } } return a; } /** * 插入排序 * shellSort(int[] a,int[] d,int numOfD) * 希尔排序 * */ public static void shellSort(int[] a,int[] d,int numOfD){ int i, j, k, m=0, span, temp, n=a.length; for(m=0;m<numOfD;m++){ span=d[m]; for(k=0;k<span;k++){ for(i=k;i<n-span;i=i+span){ temp=a[i+span]; j=i; while(j>-1&&temp<=a[j]){ a[j+span]=a[j]; j=j-span; } a[j+span]=temp; } } } } /** * 交换排序 * 冒泡排序 * bullboSort(int[] a3) * */ public static int[] bullboSort(int[] a3){ int i=0, j=0, flag=1, temp=0, n=a3.length; for(i=1;i<n&&flag==1;i++){ flag=0; for(j=0;j<n-1;j++){ if(a3[j]>a3[j+1]){ flag=1; temp=a3[j]; a3[j]=a3[j+1]; a3[j+1]=temp; } } } return a3; } /** * 交换排序 * 冒泡排序 * @author Allchin * bubbleSortPro(int[] a) * */ public static int[] bubbleSortPro(int[] a){ int i=0, k=0, temp=a[0]; boolean sorted=true; for(i=1;i<a.length;i++){ sorted=true;//初始化假设完成=true for(k=0;k<a.length-1;k++){ if(a[k]>a[k+1]){ temp=a[k]; a[k]=a[k+1]; a[k+1]=temp; sorted=false;//如果有排序操作,则设完成=false } } if(sorted){//如果排序已经完成(上次循环没有发生交换位置操作) return a; } } return a; } /** * 交换排序 * 快速排序 * quickSortPro(int[] a,int low ,int high) * @author Allchin * 1.从右开始扫描 * 1.1找出比目标小的数 * 1.2把比目标小的数换到目标的位置 * 2.从左扫描 * 2.1找出比目标大的数 * 2.2把比目标大的数换到目标的位置 * 3.将结束的指针位置赋予目标值 * 4.递归结束指针左边的部分 * 5.递归结束指针右边的部分 * * */ public static int[] quickSortPro(int[] a,int low ,int high){ int j=high, i=low, target=a[low]; while(i<j){ for(j=high;j>low&&i<j;j--){//从右边开始扫描 if(target>a[j]){//找到比目标小的, a[i]=a[j];//把比目标小的放到目标的位置,目标的下标成了j(暂不赋值,下面还有操作) break;//结束从右的扫描 } } for(i=low;i<high&&i<j;i++){//从左开始扫描 if(target<a[i]){//找到比目标大的 a[j]=a[i];//把比目标大的,放到目标的位置,目标的下标从j变成了i(暂不赋值,下面操作) break;//结束从左的扫描 } } //上面的过程不断重复; //比target小的不断放到i的位置,就是target的左边; //比target大的不断放到j的位置,就是target的右边; //直到i=j; } a[i]=target;//此时i=j;i的位置就是target正在所在的位置 if(low<i){//用递归,把target左边的所有元素位置确定下来 quickSortPro(a,low,i-1); } if(i<high){//用递归,把target右边的所有元素位置确定下来 quickSortPro(a,j+1,high);//这个时候i=j,写i写j都一样 } return a; } /** * 选择排序 * simChoseSort(int[] a4) * 直接选择排序 * */ public static int[] simChoseSort(int[] a4){ int i=0, j=0, temp=0, small=0, n=a4.length; for(i=0;i<n-1;i++){ small=i; for(j=i+1;j<n;j++){ if(a4[j]<a4[small]){ small=j; } if(small!=i){ temp=a4[i]; a4[i]=a4[small]; a4[small]=temp; } } } return a4; } /** * 选择排序 * 直接选择排序 * selectSortPro(int[] a) * @author Allchin * */ public static int[] selectSortPro(int[] a){ int min=a[0],//最小数的下标 i=0, temp=0, k=0; for(i=0;i<a.length;i++){ min=i; for(k=i+1;k<a.length;k++){//找出最小数的下标 min=a[k]<a[min]?k:min; } if(min!=i){//找到一个比a[i]小的数,就把他们两个交换位置 temp=a[i]; a[i]=a[min]; a[min]=temp; } } return a; } /** * 归并排序 * 二路归并排序 * mergeSort(int[] a) * */ public static void mergeSort(int[] a){ int i; int n=a.length; int k=1; int[] swap=new int[n]; while(k<n){ merge(a,swap,k); for(i=0;i<n;i++){ a[i]=swap[i]; } k=2*k; } } // 一次二路归并排序算法 // merge(int[] a,int[] swap,int k) public static void merge(int[] a,int[] swap,int k){ int n=a.length; int m=0,u1,l2,i,j,u2; int l1=0; while(l1+k<=n-1){ l2=l1+k; u1=l2-1; u2=(l2+k-1<=n-1)?l2+k-1:n-1; for(i=l1,j=l2;i<=u1&&j<=u2;m++){ if(a[i]<=a[j]){ swap[m]=a[i]; i++; } else{ swap[m]=a[i]; j++; } } while(i<=u1){ swap[m]=a[i]; m++; i++; } while(j<=u2){ swap[m]=a[j]; m++; j++; } l1=u2+1; } for(i=l1;i<n;i++,m++){ swap[m]=a[i]; } } /** * 基数排序 * radixSort(int[] a, int m, int d) * */ public static void radixSort(int[] a, int m, int d) throws Exception{ // a为要排序的数据元素,d为进制的基数,m为数据元素的最大位数 int n = a.length; int i, j, k, l, power = 1; LinQueue[] myQueue = new LinQueue[d]; //创建链式队列数组对象 for(i = 0; i < d; i++){ LinQueue temp = new LinQueue(); myQueue[i] = temp; } //进行m次排序 for(i = 0; i < m; i++){ if(i == 0) power = 1; else power = power * d; //依次将n个数据元素按第k位的大小放到相应的队列中 for(j = 0; j < n; j++){ k = a[j] / power - (a[j] / (power * d)) * d; //计算k值 myQueue[k].append(new Integer(a[j])); // a[j]入队列k } //顺序回收各队列中的数据元素到数组a中 l = 0; for(j = 0; j < d; j++){ while(myQueue[j].notEmpty()){ a[l] = ((Integer)myQueue[j].delete()).intValue(); l++; } } } } /** * 选择排序 * 堆排序 * heapSort(int[] a) * */ public static void heapSort(int[] a){ int temp; int n = a.length; initCreateHeap(a); //初始化创建最大堆 for(int i = n - 1; i > 0; i --){ //当前最大堆个数每次递减1 //把堆顶a[0]元素和当前最大堆的最后一个元素交换 temp = a[0]; a[0] = a[i]; a[i] = temp; createHeap(a,i, 0); //调整根结点满足最大堆 } } public static void createHeap(int[] a, int n, int h){ int i, j, flag; int temp; i = h; // i为要建堆的二叉树根结点下标 j = 2 * i + 1; // j为i结点的左孩子结点的下标 temp = a[i]; flag = 0; //沿左右孩子中值较大者重复向下筛选 while(j < n && flag != 1){ //寻找左右孩子结点中的较大者,j为其下标 if(j < n - 1 && a[j] < a[j + 1]) j++; if (temp > a[j]) //a[i]>a[j] flag = 1; //标记结束筛选条件 else{ //否则把a[j]上移 a[i] = a[j]; i = j; j = 2 * i + 1; } } a[i] = temp; //把最初的a[i]赋予最后的a[j] } public static void initCreateHeap(int[] a){ int n = a.length; for(int i = (n - 1) / 2; i >= 0; i --) createHeap(a, n, i); } } package tools; import java.io.*; import java.util.*; public class TimeTest { /** * valiables * */ public static PrintStream out=System.out; private double startTime=0, endTime=0, times=0; private String title=""; /** * Methods * */ public void runWhat() { } /** * doItForTimes(int times,String title) * 流程控制 * 适用于整个类测试,这个类是本类的子类,并重写runWhat方法 * */ public void doItForTimes(int times,String title) { start(times,title); for(int i=0;i<times;i++){//执行run方法 runWhat(); } stop(); } /** * start(int times,String title) * */ public void start(int times,String title){ this.times=times; this.title=title; out.println("Methods`"+title+"` will run for `"+times+"`times"); startTime=new Date().getTime();//开始计时 } /** * stop() * */ public void stop(){ endTime=new Date().getTime();//结束计时 out.println("Methods`"+title+"` had run for `"+times+"`times in`"+((endTime-startTime)/1000)+"`seconds"); out.println("Each of the Methods`"+title+"` spends `"+(((endTime-startTime)/times)/1000)+"` seconds"); out.println(); } } package Exp5; public interface Queue{ public void append(Object obj) throws Exception; public Object delete() throws Exception; public Object getFront() throws Exception; public boolean notEmpty(); } package Exp5; public class Node{ Object element; Node next; Node(Object obj,Node nextval){ element = obj; next = nextval; } Node(Node nextval){ next = nextval; } public Node getNext(){ return next; } public void setNext(Node nextval){ next = nextval; } public Object getElement(){ return element; } public void setElement(Object obj){ element = obj; } public String toString(){ return element.toString(); } } package Exp5; public class LinQueue implements Queue{ Node front; Node rear; int count; public LinQueue(){ initiate(); } public LinQueue(int sz){ initiate(); } private void initiate(){ front = rear = null; count = 0; } public void append(Object obj){ Node newNode = new Node(obj,null); if(rear != null) rear.next = newNode; rear = newNode; if(front == null) front = newNode; count ++; } public Object delete() throws Exception{ if(count == 0) throw new Exception("队列已空!"); Node temp = front; front = front.next; count --; return temp.getElement(); } public Object getFront() throws Exception{ if(count == 0) throw new Exception("队列已空!"); return front.getElement(); } public boolean notEmpty(){ return count != 0; } }