java基础算法--排序大全

  1 package sorting;

  2 

  3 import java.util.*;

  4 //import java.util.Comparator;

  5 //import java.util.PriorityQueue;

  6 //import java.util.Queue;

  7 

  8 public class Sorting {

  9     /************************************序言**********************************************/

 10     /**

 11      * 排序方法:冒泡排序,插入排序,希尔排序,堆排序(2),归并排序(2),快排(2)...

 12      * */

 13     

 14     /**

 15      * 最小值函数

 16      * */

 17     private static <AnyType extends Comparable<? super AnyType>> AnyType min(AnyType a, AnyType b){

 18         if(a.compareTo(b) <= 0)

 19             return a;

 20         else 

 21             return b;

 22     }

 23     

 24     /**

 25      * 交换函数

 26      * */

 27     private static <AnyType extends Comparable<? super AnyType>> void swap(AnyType [] a, int m, int n){

 28         AnyType tmp = a[n];

 29         a[n] = a[m];

 30         a[m] = tmp;        

 31     }

 32     /**********************************BubleSort*****************************************/

 33     /**

 34      * 冒泡排序:BubleSort

 35      * 每次内层循环最大的都被滤到最后

 36      * */

 37     public static <AnyType extends Comparable<? super AnyType>> void bubleSort(AnyType [] a){

 38         for(int i=0;i<a.length;i++){  

 39             for(int j=0;j<a.length-1-i;j++){  

 40                 if(a[j].compareTo(a[j+1]) > 0){   //如果后一个数小于前一个数交换  

 41                     AnyType tmp=a[j];  

 42                     a[j]=a[j+1];  

 43                     a[j+1]=tmp;  

 44                 }  

 45             }  

 46         }             

 47     }

 48     /*************************SelectSort*************************************************/

 49     /***

 50      * 选择排序:SelectSort

 51      * 每次内层循环最小的被滤到最前

 52      */

 53      public static <AnyType extends Comparable<? super AnyType>> void selectSort(AnyType[] a) {

 54             int minIndex;     

 55             for (int i = 0; i < a.length; i++) {

 56                 minIndex = i;                

 57                 for (int j = i + 1; j < a.length; j++) {                   

 58                     if ((a[j].compareTo(a[minIndex])) < 0) {

 59                         minIndex = j;

 60                     }

 61                 }                

 62                 swap(a, i, minIndex);

 63             }

 64         }

 65 

 66     /*************************InsertionSort**********************************************/    

 67     /***

 68      * 插入排序:InsertionSort 

 69      * @param a

 70      * 插入排序的实质是从a[1]~a[a.length-1]开始,逐个比较a[p](p=1,2,...,a.length-1)与a[j-1]的值,直至找到a[p]的位置。

 71      */     

 72     public static <AnyType extends Comparable<? super AnyType>> void insertionSort(AnyType [] a){

 73         int j;

 74         for(int p = 1; p < a.length; p++){

 75             AnyType tmp = a[p]; //务必使用tmp变量,否则可能第一轮比较过后啊a[p]也即a[j]的值被覆盖

 76             for(j = p; j > 0 && tmp.compareTo(a[j - 1])<0;j--){//等于就不挪了,省一次操作

 77                 a[j] = a[j-1];

 78             }

 79             a[j] = tmp;

 80             

 81         }

 82     }

 83     /*************************ShellSort**********************************************/

 84     /**

 85      * 希尔排序:ShellSort 最坏情形:O(N2)

 86      * @param a

 87      * 希尔排序(即间隔排序)的作用:对于间隔k,希尔排序即对k个独立的子数组的一次插入排序

 88      */

 89     public static <AnyType extends Comparable<? super AnyType>> void shellSort(AnyType [] a){

 90         int j;

 91         for(int gap = a.length / 2; gap > 0; gap /= 2 ){

 92             //同时对k个子数组进行间隔排序,相当于和并单独子数组排序的两个for循环 for(int i=0;i<gap;i++){for(int p=i;i<a.length;p+=gap){}}

 93             for(int i = gap;i < a.length;i++){

 94                 //每个子数组的插入排序

 95                 AnyType tmp = a[i];

 96                 for(j = i;j >= gap && tmp.compareTo(a[j-gap])<0;j-=gap){//等于就不挪了,省一次操作

 97                     a[j] = a[j-gap];

 98                 }

 99                 a[j] = tmp;

100             }

101         }

102     }

103     /*************************HeapSort**********************************************/

104     /**

105      * 堆排序:HeapSort1   最坏情形:O(Nlog(N)) 堆排序要比希尔排序要慢

106      * @param a

107      * 堆排序使用优先队列java.util.PriorityQueue实现

108      */        

109     public static <AnyType extends Comparable<? super AnyType>> void heapSort1(AnyType [] a){

110         Comparator<AnyType> comparator = new Comparator<AnyType>(){

111             public int compare(AnyType left, AnyType right){

112                 return left.compareTo(right) ;

113              }

114         };

115         Queue<AnyType> heap = new PriorityQueue<AnyType>(a.length,comparator);

116         for(AnyType e:a){

117             heap.add(e);

118         }

119         int i = 0;

120         while(!heap.isEmpty()){

121             a[i++] = heap.poll();

122         }        

123     }

124     /****************************************************************************************/

125     /**

126      * 堆排序:HeapSort2 最坏情形:O(Nlog(N))

127      * @param a

128      * 使用基础代码实现,建堆,排序

129      */

130     /**

131      * 求左子节点

132      * */

133     private static int leftChild(int i){

134         return 2 * i + 1;

135     }

136     /**

137      * 下滤函数:deleteMin(deleteMax)时候使用

138      * 对于大根堆下滤期间,大数被逐次滤上去(一步一步),小数被一直滤到它该到的位置(for结束后)

139      * @param a 堆数组

140      * @param i 开始下滤的起点

141      * @param n 堆的有效数组长度,随着不断deleteMax操作,堆中元素会不断减少,有效数组长度n也会逐渐减小

142      */

143      private static <AnyType extends Comparable<? super AnyType>> void percolateDown(AnyType[] a, int i, int n){

144          int child;//左右子中较小的那个节点

145          AnyType tmp = a[i];

146          

147          for(; leftChild(i)< n; i = child){//leftChild(i)< n 判断是否到达最后一个叶子节点

148              child = leftChild(i);

149              //如果只有一个左子节点,那么不必判断那个更大了

150              if(child != n-1 && a[child].compareTo( a[child + 1] ) < 0)//child!=n-1为了确定是否有两个子节点

151                  child++;//将两个儿子中大的那个滤上去

152              if(tmp.compareTo( a[child]) < 0 ){//等于就不挪了,省一次操作

153                  a[i]=a[child];//大数被逐次滤上去(一步一步)

154              }else

155                  break;

156          }

157          a[i]=tmp;//小数被for一直滤下来         

158      }

159 

160     /**

161      * 排序结果:升序 ,使用大根堆

162      * 建立大根堆,deleteMin操作,得到排序数组

163      * 下虑操作:在建立二叉堆和deleteMin中都有使用

164      * */

165     public static <AnyType extends Comparable<? super AnyType>> void heapSort2(AnyType [] a){

166         /*  在无序数组上直接下滤建立大根堆

167          *  从低向上开始下滤,即最后一个节点的父节点下滤即a[length/2]

168          *  堆从数组索引0开始,因此左子节点为2*i+1,右子节点为2*i+2  

169          *  */

170         for(int i = a.length/2; i >= 0; i--){

171             percolateDown(a, i, a.length);

172         }

173         /*  堆排序:不断deleteMax将堆中最大的元素放置于数组a的末端

174          *  */

175         for(int j = a.length-1; j >= 0; j--){

176             //deleteMax

177             AnyType tmp = a[j];

178             a[j] = a[0];

179             //将队尾元素放置堆根处,开始下滤

180             a[0] = tmp;

181             percolateDown(a, 0, j);//初始时刻j为a.length-1

182         }

183     }

184     /*************************MergeSort**********************************************/

185     /**

186      * 归并排序:MergeSort1  最坏运行时间O(Nlog(N)) 对空间有要求,线性内存    比较次数最少

187      * 注意: 归并排序严重依赖于比较元素和数组中移动元素的相对开销,是语言相关的。

188      *               其中:java中,执行一次泛型排序(Comparator)时 ,比较(不容易内嵌,动态调度)的的开销要大于移动元素(引用赋值);由于比较次数最少,是标准java类库中泛型排序所使用的算法。

189      *     而 C++则相反,其泛型排序中如果对象庞大,拷贝对象开销大,比较相对省时。C++库中使用快速排序方法。

190      * @param a

191      * 实现方式:递归,本质就是一直讲待排序的数组二分下去,直至每一半均只有一个元素然后依次合并,完成排序。

192      * */

193     

194     /**

195      * 实际完成归并排序的过程的程序

196      * */

197     private static <AnyType extends Comparable<? super AnyType>> void merge(AnyType [] a, AnyType [] tmpArray, int leftPos, int rightPos, int rightEnd){

198         int leftEnd = rightPos - 1;

199         int tmpPos = leftPos;

200         int numElements = rightEnd - leftPos + 1;

201         

202         while(leftPos <= leftEnd && rightPos <= rightEnd){

203             if(a[leftPos].compareTo(a[rightPos]) <= 0)//等不等于都得拷贝

204                 tmpArray[tmpPos++] = a[leftPos++];

205             else

206                 tmpArray[tmpPos++] = a[rightPos++];

207         }        

208         while(leftPos <= leftEnd){

209             tmpArray[tmpPos++] = a[leftPos++];

210         }

211         while(rightPos <= rightEnd){

212             tmpArray[tmpPos++] = a[rightPos++];

213         }

214         for(int i = numElements; i >0; i--){

215             a[rightEnd] = tmpArray[rightEnd];

216             rightEnd--;//注意rightEnd要单独拿出来自减,否则在上个语句中会自减两次

217         }

218     }

219     

220     /**

221      * 主递归程序

222      * */

223     private static <AnyType extends Comparable<? super AnyType>> void mergeSort(AnyType [] a, AnyType [] tmpArray, int left, int right){

224         if(left < right){

225             int center = (left + right)/2;

226             mergeSort(a, tmpArray, left, center);

227             mergeSort(a, tmpArray, center + 1, right);

228             merge(a, tmpArray, left, center + 1, right);//实际完成排序过程

229         }

230     }

231     

232     /**

233      * 归并排序驱动程序

234      * */

235     public static <AnyType extends Comparable<? super AnyType>> void MergeSort1(AnyType [] a){

236         AnyType [] tmpArray = (AnyType[]) new Comparable[a.length];

237         mergeSort(a, tmpArray, 0, a.length - 1);

238     }    

239     

240     /********************************************************************************/

241     /**

242      * 归并排序:MergeSort2  最坏运行时间O(Nlog(N))

243      * @param a

244      * 实现方式:非递归,从单个元素开始归并合成小组,然后小组之间归并直至归并成一个完整的数组,依旧使用MergeSort1使用的merge函数

245      * */    

246     public static <AnyType extends Comparable<? super AnyType>> void MergeSort2(AnyType [] a){

247         int n = a.length;

248         AnyType[] tmpArray = (AnyType[]) new Comparable[n]; 

249         for(int subList = 1; subList < n; subList *=2){

250             int leftPos = 0;

251             while(leftPos + subList < n){

252                 int rightPos = leftPos + subList;

253 //                int leftEnd = rightPos - 1;

254                 int rightEnd = min(n-1, rightPos + subList - 1); //一定要注意不能越界 min

255                 merge(a, tmpArray, leftPos, rightPos, rightEnd);

256                 leftPos = rightEnd + 1;  //等同于leftPos += 2 * subList;                

257             }

258         }

259     }

260     /*************************QuickSort**********************************************/

261     /**

262      * 快速排序:QuickSort1  平均运行时间:O(NlogN) 最坏运行时间:O(N2)

263      * 使用三数中值分割法选取枢纽元

264      * 由于对于小数组(N<=20),快速排序的递归会不如插入排序,因此该程序调用插入排序函数。截止范围CUTOFF=10

265      * */

266     

267     

268     /**

269      * 三数中值分割法:取左端,右端,中心位置的三个元素的中值作为枢纽元

270      * 实在值得注意的一点是:三数中值分割法有效的条件是left+2<=right(即至少要有三个元素)的时候才成立,对于2个及2个一下元素将会出现错误。

271      * 排序后最小的将位于a[left],最大的位于a[right],枢纽元即中间值a[center]将被放置于a[right-1](亦即交换a[center]与a[right-1])

272      * 这样在分隔阶段,i,j将从left+1和right-2开始比较

273      * 三数中值分割法的好处:a[left]比枢纽元小,将作为j的警戒标记;而a[right-1]存放着枢纽元,则自然作为i的警戒标记。

274      * */

275     private static <AnyType extends Comparable<? super AnyType>> AnyType median3(AnyType [] a, int left, int right){

276         int center = (left +  right)/2;

277         if(a[center].compareTo(a[left]) < 0)

278             swap(a, center, left);

279         if(a[right].compareTo(a[left]) < 0)

280             swap(a, right, left);

281         if(a[right].compareTo(a[center]) < 0)

282             swap(a, right, center);

283         //将枢纽元至于a[right - 1]的位置上

284         swap(a, center, right - 1);

285         return a[right - 1];        

286     }

287     /**

288      * 分割策略

289      * */

290     private static <AnyType extends Comparable<? super AnyType>> int partition(AnyType [] a, int left, int right){

291         AnyType pivot = median3(a, left, right);

292         //由于pivot放置在了a[right - 1]的位置(暂存pivot),因此i,j的取值应该为 left + 1,和right - 2

293         int i = left, j = right - 1;

294         for(;;){

295             //在遇到i,j处值都等于pivot时候停下,但是还得继续道,j<i才算结束,因此while编写要格外注意

296             while(a[++i].compareTo(pivot) < 0){}//遇到跟pivot枢纽元值相等的值要停下,否则N2效率低下

297             while(a[--j].compareTo(pivot) > 0){}

298             if(i < j)

299                 swap(a, i, j);

300             else

301                 break;                

302         }

303 //        for(;;){

304 //            while(a[i].compareTo(pivot) < 0){i++;}

305 //            while(a[j].compareTo(pivot) > 0){j--;}

306 //            if(i < j){

307 //                swap(a, i, j);

308 //                i++;j--;

309 //            }

310 //            else

311 //                break;                

312 //        }

313         swap(a, i, right - 1);

314         return i;

315     }

316     /**

317      * 快速排序递归程序,主体程序,遇到跟pivot枢纽元值相等的值要停下

318      * 前提条件:left+1<right(即left+2<=right)

319      * 实在值得注意的一点是:三数中值分割法有效的条件是left+2<=right(即至少要有三个元素)的时候才成立,对于2个及2个一下元素将会出现错误;

320      *                 而这里当CUTOFF设置为1时候,仍旧没有错误的原因是else条件下的insertionSort(a)起了作用

321      * */

322     private static final int CUTOFF = 10;//CUTOFF>=2

323     private static <AnyType extends Comparable<? super AnyType>> void qSort(AnyType [] a, int left, int right){

324         //利用截止范围判断数据量

325         if(left + CUTOFF <= right){

326             //获取枢纽元

327 //            AnyType pivot = median3(a, left, right);

328 //            //由于pivot放置在了a[right - 1]的位置(暂存pivot),因此i,j的取值应该为 left + 1,和right - 2

329 //            int i = left, j = right - 1;

330 //            for(;;){

331 //                //在遇到i,j处值都等于pivot时候停下,但是还得继续道,j<i才算结束,因此while编写要格外注意

332 //                while(a[++i].compareTo(pivot) < 0){}//遇到跟pivot枢纽元值相等的值要停下,否则N2效率低下

333 //                while(a[--j].compareTo(pivot) > 0){}

334 //                if(i < j)

335 //                    swap(a, i, j);

336 //                else

337 //                    break;                

338 //            }

339 //            for(;;){

340 //                while(a[i].compareTo(pivot) < 0){i++;}

341 //                while(a[j].compareTo(pivot) > 0){j--;}

342 //                if(i < j){

343 //                    swap(a, i, j);

344 //                    i++;j--;

345 //                }

346 //                else

347 //                    break;                

348 //            }

349             //因为i左边都比pivot小,i及i右边除了right-1除存放着pivot外都比pivot大,因此将i处值与right-1处值交换

350             //即得到i左边都比其小,右边都比其大,i即pivot排序好的正确位置(换回pivot)

351 //            swap(a, i, right - 1);

352             int i = partition(a, left, right);

353             //i已排好序

354             qSort(a, left, i - 1);

355             qSort(a, i + 1, right);

356         }else{

357             insertionSort(a);//在这里处理了当CUTOFF等于1时的情景不会出错。当CUTOFF等于0时首先是不允许的(那样left就等于right了),其次这会导致median3()函数数组索引越界异常

358             }

359     }

360     /**

361      * 快速排序驱动程序

362      * */

363     public static <AnyType extends Comparable<? super AnyType>> void quickSort(AnyType [] a){

364         qSort(a, 0, a.length - 1);

365     }

366     

367     /*********************************QuickSort2***************************************/

368     /**

369      * 分割策略

370      * */

371     private static <AnyType extends Comparable<? super AnyType>> int partition2(AnyType [] a, int start, int end){

372         int i = start, j = end;

373         AnyType base = a[start];            

374         while(i < j ){

375             while((a[j].compareTo(base) > 0) && (j > i))

376                 j--;

377             if(i < j){

378                 a[i] = a[j];

379                 i++;//

380             }

381             while((a[i].compareTo(base) < 0) && (i < j))

382                 i++;

383             if(i < j){

384                 a[j] = a[i];

385                 j--;//

386             }            

387                     

388         }//while

389         a[i] = base;

390         return i;

391     }

392     /**

393      * 使用数组第一位作为枢纽元

394      * 前提条件:start<end

395      * */

396     private static <AnyType extends Comparable<? super AnyType>> void qSort2(AnyType [] a, int start, int end){

397         if(start < end){

398 //            int i = start, j = end;

399 //            AnyType base = a[start];            

400 //            while(i < j ){

401 //                while((a[j].compareTo(base) > 0) && (j > i))

402 //                    j--;

403 //                if(i < j){

404 //                    a[i] = a[j];

405 //                    i++;//

406 //                }

407 //                while((a[i].compareTo(base) < 0) && (i < j))

408 //                    i++;

409 //                if(i < j){

410 //                    a[j] = a[i];

411 //                    j--;//

412 //                }            

413 //                        

414 //            }//while

415 //            a[i] = base;

416             int i = partition2(a, start, end);

417             

418             qSort2(a, start, i-1);

419             qSort2(a, i+1, end);

420         }

421         

422     }

423     /**

424      * 驱动程序

425      * 使用数组第一位作为枢纽元

426      * */

427     public static <AnyType extends Comparable<? super AnyType>> void quickSort2(AnyType [] a){

428         qSort2(a, 0, a.length-1);

429     }

430     /*********************************QuickSort3***************************************/

431     /**

432      * 三数中值分割的使用非递归的快速排序

433      * */

434     public static <AnyType extends Comparable<? super AnyType>> void quickSort3(AnyType [] a){

435          if(a==null||a.length<=0)return;  

436             Stack<Integer> index=new Stack<Integer>();  

437             int start=0;  

438             int end=a.length-1;  

439               

440             int pivotPos;  

441                   

442             index.push(start);  

443             index.push(end);  

444                   

445             while(!index.isEmpty()){  

446                 end=index.pop();  

447                 start=index.pop();  

448                 if(start+1<end){//三数中值必备

449                     pivotPos=partition(a,start,end); 

450                     

451                     if(start<pivotPos-1){  

452                         index.push(start);  

453                         index.push(pivotPos-1);  

454                     }  

455                     if(end>pivotPos+1){  

456                         index.push(pivotPos+1);  

457                         index.push(end);  

458                      

459                     }

460                 }else{//三数中值必备

461                     if(a[start].compareTo(a[end])>0)

462                         swap(a, start, end);

463                 }

464             }     

465     }

466     /*********************************QuickSort4***************************************/

467     /**

468      * 使用第一值为枢纽元的使用非递归的快速排序

469      * */

470     public static <AnyType extends Comparable<? super AnyType>> void quickSort4(AnyType [] a){

471          if(a==null||a.length<=0)return;  

472             Stack<Integer> index=new Stack<Integer>();  

473             int start=0;  

474             int end=a.length-1;  

475               

476             int pivotPos;  

477                   

478             index.push(start);  

479             index.push(end);  

480                   

481             while(!index.isEmpty()){  

482                 end=index.pop();  

483                 start=index.pop();  

484 //                if(start<end){  //可有可无,因为压栈的时候已能确定start<end,此处判断是恒成立的

485                     pivotPos=partition2(a,start,end); 

486                     

487                     if(start<pivotPos-1){  

488                         index.push(start);  

489                         index.push(pivotPos-1);  

490                     }  

491                     if(end>pivotPos+1){  

492                         index.push(pivotPos+1);  

493                         index.push(end);  

494                      

495                     }

496 //                }

497             }     

498     }

499 

500     /*-----------------------------------------main-------------------------------------------------*/

501     public static void main(String[] args) {

502         // TODO Auto-generated method stub

503         /**

504          * Test case: Sort the array.

505          * */        

506 //        Integer[] a ={3,1,4,1,5,9,111,2,6,142,543,123,65,453,123,879,572,434,111,242,811,102};

507         Integer[] a ={3,1,4,1,5,9,2,6};

508         System.out.println("Before sorting:");

509         for(Integer i:a){

510             System.out.print(i+",");

511         }

512         System.out.println();

513         

514         Sorting.quickSort4(a);//排序方法调用

515         System.out.println("After sorting:");

516         for(Integer i:a){

517             System.out.print(i+",");

518         }

519         System.out.println();

520 

521         

522     }

523 

524 }

 

你可能感兴趣的:(java基础)