java几种常见的排序算法总结

时间:2023-03-09 15:14:56
java几种常见的排序算法总结
  1. /*************几种常见的排序算法总结***************************/
  2. package paixu;
  3. public class PaiXu {
  4. final int MAX=20;
  5. int num[]=new int[MAX];
  6. {
  7. System.out.print("生成的随机数组是:");
  8. for(int i=0;i<20;i++){
  9. num[i]=(int)(Math.random()*100);
  10. System.out.print(num[i]+" ");
  11. }
  12. System.out.println();
  13. }
  14. int num2[]=new int[MAX]; //只用于合并排序法中
  15. {
  16. System.out.print("合并排序法需要使用的数组2是:");
  17. for(int i=0;i<20;i++){
  18. num2[i]=(int)(Math.random()*100);
  19. System.out.print(num2[i]+" ");
  20. }
  21. System.out.println();
  22. }
  23. int num3[]=new int[MAX+MAX]; //用于存放合并排序法中被合并排序好的数组
  24. public PaiXu(){
  25. selsort(num.clone());                        //选择排序法
  26. insort(num.clone());                         //插入排序法
  27. bubsort(num.clone());                        //冒泡排序法
  28. shellsort(num.clone());                      //希尔排序法
  29. shakersort(num.clone());                     //shake排序法
  30. heapsort(num.clone());                       //堆排序
  31. quicksort_one(num.clone());                  //快速排序法(一)
  32. quicksort_two(num.clone());                  //快速排序法(二)
  33. quicksort_three(num.clone());                //快速排序法(三)
  34. mergesort(num.clone(),num2.clone(),num3);    //合并排序法
  35. basesort(num.clone());                       //基数排序法
  36. }
  37. /*----------------------------选择排序法-------------------------------------------
  38. 将要排序的对象分作两部份,一个是已排序的,一个是未排序的,从后端未排序部份选择一个最小值,并放入前端已排序部份的最后一个。
  39. -------------------------------------------------------------------------------*/
  40. public void selsort(int number[]) {
  41. int i, j, k, m, temp;
  42. long start,end;
  43. start=System.nanoTime();
  44. for(i = 0; i < MAX-1; i++) {
  45. m = i;
  46. for(j = i+1; j < MAX; j++){
  47. if(number[j] < number[m]){
  48. m = j;
  49. }
  50. }
  51. if( i != m){
  52. temp=number[i];
  53. number[i]=number[m];
  54. number[m]=temp;
  55. }
  56. }
  57. end=System.nanoTime();
  58. System.out.println("-----------------选择排序法------------------");
  59. System.out.print("排序后是:");
  60. for(i=0;i<=MAX-1;i++){
  61. System.out.print(number[i]+" ");
  62. }
  63. System.out.println();
  64. System.out.println("排序使用时间:"+(end-start)+" ns");
  65. }
  66. /*-------------------------插入排序法--------------------------------
  67. 像是玩朴克一样,我们将牌分作两堆,每次从后面一堆的牌抽出最前端的牌,然后插入前面一堆牌的适当位置
  68. -----------------------------------------------------------------*/
  69. public void insort(int number[]){
  70. int i, j, k, temp;
  71. long start,end;
  72. start=System.nanoTime();
  73. for(j = 1; j < MAX; j++) {
  74. temp = number[j];
  75. i = j - 1;
  76. while(temp < number[i]) {
  77. number[i+1] = number[i];
  78. i--;
  79. if(i == -1){
  80. break;
  81. }
  82. }
  83. number[i+1] = temp;
  84. }
  85. end=System.nanoTime();
  86. System.out.println("-----------------插入排序法------------------");
  87. System.out.print("排序后是:");
  88. for(i=0;i<=MAX-1;i++){
  89. System.out.print(number[i]+" ");
  90. }
  91. System.out.println();
  92. System.out.println("排序使用时间:"+(end-start)+" ns");
  93. }
  94. /*-----------------------------------------冒泡排序法----------------------------------------
  95. 顾名思义,就是排序时,最大的元素会如同气泡一样移至右端,其利用比较相邻元素的方法,将大的元素交换至右端,
  96. 所以大的元素会不断的往右移动,直到适当的位置为止。
  97. 基本的气泡排序法可以利用旗标的方式稍微减少一些比较的时间,当寻访完阵列后都没有发生任何的交换动作,
  98. 表示排序已经完成,而无需再进行之后的回圈比较与交换动作。
  99. ----------------------------------------------------------------------------------------*/
  100. public void bubsort(int number[]){
  101. int i, j, k, temp, flag = 1;
  102. long start,end;
  103. start=System.nanoTime();
  104. for(i = 0; i < MAX-1 && flag == 1; i++) {
  105. flag = 0;
  106. for(j = 0; j < MAX-i-1; j++) {
  107. if(number[j+1] < number[j]) {
  108. temp=number[j+1];
  109. number[j+1]=number[j];
  110. number[j]=temp;
  111. flag = 1;
  112. }
  113. }
  114. }
  115. end=System.nanoTime();
  116. System.out.println("-----------------冒泡排序法------------------");
  117. System.out.print("排序后是:");
  118. for(i=0;i<=MAX-1;i++){
  119. System.out.print(number[i]+" ");
  120. }
  121. System.out.println();
  122. System.out.println("排序使用时间:"+(end-start)+" ns");
  123. }
  124. /*--------------------------shell(希尔)排序法----------------------------
  125. Shell首先将间隔设定为n/2,然后跳跃进行插入排序,再来将间隔n/4,跳跃进行排序动作,再来
  126. 间隔设定为n/8、n/16,直到间隔为1之后的最后一次排序终止,由于上一次的排序动作都会将
  127. 固定间隔内的元素排序好,所以当间隔越来越小时,某些元素位于正确位置的机率越高,因此
  128. 最后几次的排序动作将可以大幅减低。
  129. ---------------------------------------------------------------------*/
  130. public void shellsort(int number[]) {
  131. int i, j, k, gap, temp;
  132. long start,end;
  133. start=System.nanoTime();
  134. gap = MAX / 2;
  135. while(gap > 0) {
  136. for(k = 0; k < gap; k++) {
  137. for(i = k+gap; i < MAX; i+=gap) {
  138. for(j = i - gap; j >= k; j-=gap) {
  139. if(number[j] > number[j+gap]) {
  140. temp=number[j];
  141. number[j]=number[j+gap];
  142. number[j+gap]=temp;
  143. }else{
  144. break;
  145. }
  146. }
  147. }
  148. }
  149. gap /= 2;
  150. }
  151. end=System.nanoTime();
  152. System.out.println("-----------------shell(希尔)排序法(改进的插入排序法)------------------");
  153. System.out.print("排序后是:");
  154. for(i=0;i<=MAX-1;i++){
  155. System.out.print(number[i]+" ");
  156. }
  157. System.out.println();
  158. System.out.println("排序使用时间:"+(end-start)+" ns");
  159. }
  160. /*---------------------Shake排序法(改良的冒泡排序法)--------------------------
  161. 方法就在于气泡排序的双向进行,先让气泡排序由左向右进行,再来让气泡排序由右往左进行,
  162. 如此完成一次排序的动作,而您必须使用left与right两个旗标来记录左右两端已排序的元素位置。
  163. --------------------------------------------------------------------*/
  164. public void shakersort(int number[]) {
  165. int i, temp, left = 0, right = MAX - 1, shift = 0;
  166. long start,end;
  167. start=System.nanoTime();
  168. while(left < right) {
  169. // 向右進行氣泡排序
  170. for(i = left; i < right; i++) {
  171. if(number[i] > number[i+1]) {
  172. temp=number[i];
  173. number[i]=number[i+1];
  174. number[i+1]=temp;
  175. shift = i;
  176. }
  177. }
  178. right = shift;
  179. // 向左進行氣泡排序
  180. for(i = right; i > left; i--) {
  181. if(number[i] < number[i-1]) {
  182. temp=number[i];
  183. number[i]=number[i-1];
  184. number[i-1]=temp;
  185. shift = i;
  186. }
  187. }
  188. left = shift;
  189. }
  190. end=System.nanoTime();
  191. System.out.println("-----------------shake排序法(改进的冒泡排序法)------------------");
  192. System.out.print("排序后是:");
  193. for(i=0;i<=MAX-1;i++){
  194. System.out.print(number[i]+" ");
  195. }
  196. System.out.println();
  197. System.out.println("排序使用时间:"+(end-start)+" ns");
  198. }
  199. /*-----------------------heap排序(堆排序法--改进的选择排序)----------------------------
  200. 利用堆积树的原理,先构造一个堆积树(看堆积树的定义,笔记本上有),然后将根节点与最后的叶子节点交换,并屏蔽掉最后一个叶子节点,
  201. 然后再将未被屏蔽的部分重新构造堆积树,然后再重复上面的步骤,直到所有的数被按顺序排好。
  202. --------------------------------------------------------------------------------*/
  203. public void heapsort(int number[]) {
  204. int i, m, p, s, temp;
  205. long start,end;
  206. start=System.nanoTime();
  207. int number_temp[]=new int[MAX+1];
  208. for(int temp_i=1;temp_i<MAX+1;temp_i++){
  209. number_temp[temp_i]=number[temp_i-1];
  210. }
  211. createheap(number_temp);
  212. m = MAX;
  213. while(m > 1) {
  214. temp=number_temp[1];
  215. number_temp[1]=number_temp[m];
  216. number_temp[m]=temp;
  217. m--;
  218. p = 1;
  219. s = 2 * p;
  220. while(s <= m) {
  221. if(s < m && number_temp[s+1] > number_temp[s])
  222. s++;
  223. if(number_temp[p] >= number_temp[s])
  224. break;
  225. temp=number_temp[p];
  226. number_temp[p]=number_temp[s];
  227. number_temp[s]=temp;
  228. p = s;
  229. s = 2 * p;
  230. }
  231. }
  232. for(int temp_j=1;temp_j<MAX+1;temp_j++){
  233. number[temp_j-1]=number_temp[temp_j];
  234. }
  235. end=System.nanoTime();
  236. System.out.println("-----------------heap排序(堆排序法--改进的选择排序)------------------");
  237. System.out.print("排序后是:");
  238. for(i=0;i<=MAX-1;i++){
  239. System.out.print(number[i]+" ");
  240. }
  241. System.out.println();
  242. System.out.println("排序使用时间:"+(end-start)+" ns");
  243. }
  244. //将原数组构造为从下标1开始的一个新数组,便于处理,同时将这个新数组构造为最初始的堆积树结构
  245. public void createheap(int number[]) {
  246. int i, s, p, temp;
  247. int heap[] = new int[MAX+1];
  248. for(i = 1; i <= MAX; i++) {
  249. heap[i] = number[i];
  250. s = i;
  251. p = i / 2;
  252. while(s >= 2 && heap[p] < heap[s]) {
  253. temp=heap[p];
  254. heap[p]=heap[s];
  255. heap[s]=temp;
  256. s = p;
  257. p = s / 2;
  258. }
  259. }
  260. for(i = 1; i <= MAX; i++){
  261. number[i] = heap[i];
  262. }
  263. }
  264. /*-----------------------快速排序法(一)---------------------------------------------
  265. 这边所介绍的快速演算如下:将最左边的数设定为轴,并记录其值为s
  266. 廻圈处理:
  267. 令索引i 从数列左方往右方找,直到找到大于s 的数
  268. 令索引j 从数列左右方往左方找,直到找到小于s 的数
  269. 如果i >= j,则离开回圈
  270. 如果i < j,则交换索引i与j两处的值
  271. 将左侧的轴与j 进行交换
  272. 对轴左边进行递回
  273. 对轴右边进行递回
  274. --------------------------------------------------------------------------------*/
  275. public void quicksort_one(int number[]){
  276. long start,end;
  277. start=System.nanoTime();
  278. quicksort_1(number,0,MAX-1);
  279. end=System.nanoTime();
  280. System.out.println("-----------------快速排序法( 一 )------------------");
  281. System.out.print("排序后是:");
  282. for(int i=0;i<=MAX-1;i++){
  283. System.out.print(number[i]+" ");
  284. }
  285. System.out.println();
  286. System.out.println("排序使用时间:"+(end-start)+" ns");
  287. }
  288. public void quicksort_1(int number[],int left,int right) {
  289. int i, j, s, temp;
  290. if(left < right) {
  291. s = number[left];
  292. i = left;
  293. j = right + 1;
  294. while(true) {
  295. // 向右找
  296. while(i + 1 < number.length && number[++i] < s) ;
  297. // 向左找
  298. while(j -1 > -1 && number[--j] > s) ;
  299. if(i >= j)
  300. break;
  301. temp=number[i];
  302. number[i]=number[j];
  303. number[j]=temp;
  304. }
  305. number[left] = number[j];
  306. number[j] = s;
  307. quicksort_1(number, left, j-1); // 对左边进行递回
  308. quicksort_1(number, j+1, right); // 对右边进行递回
  309. }
  310. }
  311. /*-----------------------快速排序法(二)---------------------------------------------
  312. 在这个例子中,取中间的元素s作比较,同样的先得右找比s大的索引i,然后找比s小的
  313. 索引j,只要两边的索引还没有交会,就交换i 与j 的元素值,这次不用再进行轴的交换了,
  314. 因为在寻找交换的过程中,轴位置的元素也会参与交换的动作,例如:
  315. 41 24 76 11 45 64 21 69 19 36
  316. 首先left为0,right为9,(left+right)/2 = 4(取整数的商),所以轴为索引4的位置,比较的元素是
  317. 45,您往右找比45大的,往左找比45小的进行交换:
  318. 41 24 76* 11 [45] 64 21 69 19 *36
  319. 41 24 36 11 45* 64 21 69 19* 76
  320. 41 24 36 11 19 64* 21* 69 45 76
  321. [41 24 36 11 19 21] [64 69 45 76]
  322. 完成以上之后,再初别对左边括号与右边括号的部份进行递回,如此就可以完成排序的目的。
  323. --------------------------------------------------------------------------------*/
  324. public void quicksort_two(int number[]){
  325. long start,end;
  326. start=System.nanoTime();
  327. quicksort_2(number,0,MAX-1);
  328. end=System.nanoTime();
  329. System.out.println("-----------------快速排序法( 二 )------------------");
  330. System.out.print("排序后是:");
  331. for(int i=0;i<=MAX-1;i++){
  332. System.out.print(number[i]+" ");
  333. }
  334. System.out.println();
  335. System.out.println("排序使用时间:"+(end-start)+" ns");
  336. }
  337. public void quicksort_2(int number[], int left, int right) {
  338. int i, j, s, temp;
  339. if(left < right) {
  340. s = number[(left+right)/2];
  341. i = left - 1;
  342. j = right + 1;
  343. while(true) {
  344. while(number[++i] < s) ; // 向右找
  345. while(number[--j] > s) ; // 向左找
  346. if(i >= j)
  347. break;
  348. temp=number[i];
  349. number[i]=number[j];
  350. number[j]=temp;
  351. }
  352. quicksort_2(number, left, i-1); // 对左边进行递回
  353. quicksort_2(number, j+1, right); // 对右边进行递回
  354. }
  355. }
  356. /*-----------------------快速排序法(三)---------------------------------------------
  357. 先说明这个快速排序法的概念,它以最右边的值s作比较的标准,将整个数列分为三个部份,
  358. 一个是小于s的部份,一个是大于s的部份,一个是未处理的部份,如下所示:
  359. i           j
  360. --------|-----------|----------|s
  361. 小于s     大于s         未处理
  362. 在排序的过程中,i 与j 都会不断的往右进行比较与交换,最后数列会变为以下的状态:
  363. -------------|-----------------|s
  364. 小于s             大于s
  365. 然后将s的值置于中间,接下来就以相同的步骤会左右两边的数列进行排序的动作,如下所示:
  366. -------------|s|---------------
  367. 小于s             大于s
  368. 然后采用递归的方法重复上面的步骤,就可以实现排序了。
  369. --------------------------------------------------------------------------------*/
  370. public void quicksort_three(int number[]){
  371. long start,end;
  372. start=System.nanoTime();
  373. quicksort_3(number,0,MAX-1);
  374. end=System.nanoTime();
  375. System.out.println("-----------------快速排序法( 三 )------------------");
  376. System.out.print("排序后是:");
  377. for(int i=0;i<=MAX-1;i++){
  378. System.out.print(number[i]+" ");
  379. }
  380. System.out.println();
  381. System.out.println("排序使用时间:"+(end-start)+" ns");
  382. }
  383. public int partition(int number[], int left, int right) {
  384. int i, j, s, temp;
  385. s = number[right];
  386. i = left - 1;
  387. for(j = left; j < right; j++) {
  388. if(number[j] <= s) {
  389. i++;
  390. temp=number[i];
  391. number[i]=number[j];
  392. number[j]=temp;
  393. }
  394. }
  395. temp=number[i+1];
  396. number[i+1]=number[right];
  397. number[right]=temp;
  398. return i+1;
  399. }
  400. public void quicksort_3(int number[], int left, int right) {
  401. int q;
  402. if(left < right) {
  403. q = partition(number, left, right);
  404. quicksort_3(number, left, q-1);
  405. quicksort_3(number, q+1, right);
  406. }
  407. }
  408. /*-----------------------合并排序法---------------------------------------------
  409. 合并排序法基本是将两笔已排序的资料合并并进行排序,如果所读入的资料尚未排序,
  410. 可以先利用其它的排序方式来处理这两笔资料,然后再将排序好的这两笔资料合并。
  411. 合并排序法中用到了  快速排序法(三)
  412. --------------------------------------------------------------------------------*/
  413. public void mergesort(int number1[],int number2[],int number3[]){
  414. long start,end;
  415. start=System.nanoTime();
  416. quicksort_3(number1,0,MAX-1);
  417. quicksort_3(number2,0,MAX-1);
  418. mergesort_merge(number1,MAX,number2,MAX,number3);
  419. end=System.nanoTime();
  420. System.out.println("-----------------合并排序法------------------");
  421. System.out.print("排序后是:");
  422. for(int i=0;i<=MAX+MAX-1;i++){
  423. System.out.print(number3[i]+" ");
  424. }
  425. System.out.println();
  426. System.out.println("排序使用时间:"+(end-start)+" ns");
  427. }
  428. public void mergesort_merge(int number1[], int M, int number2[], int N, int number3[]) {
  429. int i = 0, j = 0, k = 0;
  430. while(i < M && j < N) {
  431. if(number1[i] <= number2[j]){
  432. number3[k++] = number1[i++];
  433. }else{
  434. number3[k++] = number2[j++];
  435. }
  436. }
  437. while(i < M){
  438. number3[k++] = number1[i++];
  439. }
  440. while(j < N){
  441. number3[k++] = number2[j++];
  442. }
  443. }
  444. /*-----------------------基数排序法---------------------------------------------
  445. 基数排序的方式可以采用LSD(Least sgnificant digital)或MSD(Most sgnificant digital),
  446. LSD的排序方式由键值的最右边开始,而MSD则相反,由键值的最左边开始。
  447. 以LSD为例,假设原来有一串数值如下所示:
  448. 73, 22, 93, 43, 55, 14, 28, 65, 39, 81
  449. 首先根据个位数的数值,在走访数值时将它们分配至编号0到9的桶子中:
  450. 0   1   2   3   4   5   6   7   8   9
  451. 81              65              39
  452. 43  14  55          28
  453. 93
  454. 22  73
  455. 接下来将这些桶子中的数值重新串接起来,成为以下的数列:
  456. 81, 22, 73, 93, 43, 14, 55, 65, 28, 39
  457. 接着再进行一次分配,这次是根据十位数来分配:
  458. 接下来将这些桶子中的数值重新串接起来,成为以下的数列:
  459. 0   1   2   3   4   5   6   7   8   9
  460. 28  39
  461. 14  22      43  55  65  73  81  93
  462. 14, 22, 28, 39, 43, 55, 65, 73, 81, 93
  463. 这时候整个数列已经排序完毕;如果排序的对象有三位数以上,则持续进行以上的动作直至最
  464. 高位数为止。
  465. LSD的基数排序适用于位数小的数列,如果位数多的话,使用MSD的效率会比较好,MSD的方
  466. 式恰与LSD相反,是由高位数为基底开始进行分配,其他的演算方式则都相同。
  467. --------------------------------------------------------------------------------*/
  468. public void basesort(int number[]){
  469. int temp[][] = new int[MAX][MAX];
  470. int order[] = new int[MAX];
  471. int i, j, k, n, lsd;
  472. long start,end;
  473. k = 0;
  474. n = 1;
  475. start=System.nanoTime();
  476. while(n <= 10) {
  477. for(i = 0; i < MAX; i++) {
  478. lsd = ((number[i] / n) % 10);
  479. temp[lsd][order[lsd]] = number[i];
  480. order[lsd]++;
  481. }
  482. //重新排列
  483. for(i = 0; i < MAX; i++) {
  484. if(order[i] != 0)
  485. for(j = 0; j < order[i]; j++) {
  486. number[k] = temp[i][j];
  487. k++;
  488. }
  489. order[i] = 0;
  490. }
  491. n *= 10;
  492. k = 0;
  493. }
  494. end=System.nanoTime();
  495. System.out.println("-----------------基数排序法------------------");
  496. System.out.print("排序后是:");
  497. for(int ii=0;ii<=MAX-1;ii++){
  498. System.out.print(number[ii]+" ");
  499. }
  500. System.out.println();
  501. System.out.println("排序使用时间:"+(end-start)+" ns");
  502. }
  503. public static void main(String[] args){
  504. System.out.println("以下的测试时间仅供参考...");
  505. new PaiXu();
  506. }
  507. }

以上代码的运行结果如下所示:

    1. 以下的测试时间仅供参考...
    2. 生成的随机数组是:53 82 61 70 75 31 30 68 22 56 48 23 12 74 13 85 69 62 21 55
    3. 合并排序法需要使用的数组2是:2 12 48 18 93 13 98 87 55 77 89 56 6 31 56 38 59 76 90 30
    4. -----------------选择排序法------------------
    5. 排序后是:12 13 21 22 23 30 31 48 53 55 56 61 62 68 69 70 74 75 82 85
    6. 排序使用时间:7815 ns
    7. -----------------插入排序法------------------
    8. 排序后是:12 13 21 22 23 30 31 48 53 55 56 61 62 68 69 70 74 75 82 85
    9. 排序使用时间:7475 ns
    10. -----------------冒泡排序法------------------
    11. 排序后是:12 13 21 22 23 30 31 48 53 55 56 61 62 68 69 70 74 75 82 85
    12. 排序使用时间:18008 ns
    13. -----------------shell(希尔)排序法(改进的插入排序法)------------------
    14. 排序后是:12 13 21 22 23 30 31 48 53 55 56 61 62 68 69 70 74 75 82 85
    15. 排序使用时间:11212 ns
    16. -----------------shake排序法(改进的冒泡排序法)------------------
    17. 排序后是:12 13 21 22 23 30 31 48 53 55 56 61 62 68 69 70 74 75 82 85
    18. 排序使用时间:14610 ns
    19. -----------------heap排序(堆排序法--改进的选择排序)------------------
    20. 排序后是:12 13 21 22 23 30 31 48 53 55 56 61 62 68 69 70 74 75 82 85
    21. 排序使用时间:15969 ns
    22. -----------------快速排序法( 一 )------------------
    23. 排序后是:12 13 21 22 23 30 31 48 53 55 56 61 62 68 69 70 74 75 82 85
    24. 排序使用时间:8834 ns
    25. -----------------快速排序法( 二 )------------------
    26. 排序后是:12 13 21 22 23 30 31 48 53 55 56 61 62 68 69 70 74 75 82 85
    27. 排序使用时间:9853 ns
    28. -----------------快速排序法( 三 )------------------
    29. 排序后是:12 13 21 22 23 30 31 48 53 55 56 61 62 68 69 70 74 75 82 85
    30. 排序使用时间:10533 ns
    31. -----------------合并排序法------------------
    32. 排序后是:2 6 12 12 13 13 18 21 22 23 30 30 31 31 38 48 48 53 55 55 56 56 56 59 61 62 68 69 70 74 75 76 77 82 85 87 89 90 93 98
    33. 排序使用时间:20387 ns
    34. -----------------基数排序法------------------
    35. 排序后是:12 13 21 22 23 30 31 48 53 55 56 61 62 68 69 70 74 75 82 85
    36. 排序使用时间:8495 ns