四种简单的排序算法

来源:互联网 发布:庄心妍是网络歌手吗 编辑:程序博客网 时间:2024/04/29 22:10
冒泡排序法

冒泡排序的原理很简单,拿整数数组的升序排序来说:从头到尾循环地比较相邻的两个数字,如果前一个数字比后一个大,则交换它们的位置,然后拿较大的这个数字跟下一个比较;如果前一个数字比后一个小,它们的位置不动,直接拿较大的数字跟下一个比较,这样循环一次完毕,最大的数字被排到了最后。接着开始第二轮循环,再从头到尾循环比较相信的两个数字,循环完毕后,第二大的数字被排到了倒数第二的位置上。长度为N的数组一共需要N次循环(其实最后一次没有必要),最坏的情况下(逆序),第1次循环要交换数字N-1次,第2次循环要交换数字N-2次,最后一次循环要交换0次,总共交换(N-1)*N/2 = (N^2-N)/2次,约N^2/2次(忽略N次不会有很大差别,特别是在N很大的时候)。如果数据是随机的,平均每次排序需要交换数字N^2/4次,也就是说交换次数和N^2/4成正比,由于常数不算在大O表示法中,可以忽略掉这个4,认为冒泡排序运行需要O(N^2)时间级别。 
以下是冒泡排序代码: 
Java代码  收藏代码
  1. package dsaa.array;  
  2. /** 
  3.  * @(#)ArrayUtil.java 2008-12-25 下午08:44:46 
  4.  *  
  5.  * @author Qiu Maoyuan 
  6.  * Array Util 
  7.  */  
  8. public class ArrayUtil {  
  9.   
  10.     public static void bubbleSort(int[] array){  
  11.         for(int i=0; i<array.length - 1; i++){  
  12.             for(int j=0; j<array.length - i - 1; j++){  
  13.                 if(array[j]>array[j + 1]){  
  14.                     swap(array, j, j + 1);  
  15.                 }  
  16.             }  
  17.         }  
  18.     }  
  19.   
  20.     private static void swap(int[] array, int index1, int index2) {  
  21.         int temp = array[index1];  
  22.         array[index1] = array[index2];  
  23.         array[index2] = temp;  
  24.     }  
  25. }  

选择排序法

选择排序法是冒泡排序法的改进,冒泡排序在最坏的情况下每次循环比较的时候都进行交换操作,而选择排序每循环一次只要交换数字1次。原理是:在第一次循环的时候用一个临时变量指向数组第1个位置,假设第1个位置是最小值,依次比较数组右边的其它数字,当遇到比第1个位置的数更小的值时,将临时变量指向这个更小的数的位置,循环过一次,便得到整个数组中最小的值,把它与第1个位置的数字交换,第一次循环完毕。第二次循环从第2个位置开始……一共需要N次循环(同样,最后一次也没有必要)。这样,选择排序法交换数字的次数跟数组长度成正比,用大O表示法表示为O(N)。 
下面的代码中加入了选择排序法selectionSort: 
Java代码  收藏代码
  1. package dsaa.array;  
  2. /** 
  3.  * @(#)ArrayUtil.java 2008-12-25 下午08:44:46 
  4.  *  
  5.  * @author Qiu Maoyuan 
  6.  * Array Util 
  7.  */  
  8. public class ArrayUtil {  
  9.   
  10.     public static void bubbleSort(int[] array){  
  11.         for(int i=0; i<array.length - 1; i++){  
  12.             for(int j=0; j<array.length - i - 1; j++){  
  13.                 if(array[j]>array[j + 1]){  
  14.                     swap(array, j, j + 1);  
  15.                 }  
  16.             }  
  17.         }  
  18.     }  
  19.       
  20.     public static void selectionSort(int[] array){  
  21.         for(int i=0; i<array.length - 1; i++){  
  22.             int minIndex = i;  
  23.             for(int j=i; j<array.length - 1; j++){  
  24.                 if(array[j + 1] < array[minIndex]){  
  25.                     minIndex = j + 1;  
  26.                 }  
  27.             }  
  28.             swap(array, i, minIndex);  
  29.         }  
  30.     }  
  31.   
  32.     private static void swap(int[] array, int index1, int index2) {  
  33.         int temp = array[index1];  
  34.         array[index1] = array[index2];  
  35.         array[index2] = temp;  
  36.     }  
  37. }  

插入排序法

插入排序法保持数组的前面一部分有序,并不断地把后面无序的数据插入到前面有序的一部分,同时仍然保持前面的数据有序。这里仍然用整数数组的升序排序来说明其原理:首先假设数组第1个数据为有序数组(虽然只有1个数据,但那肯定是有序的数组),然后将第2个数据与前面1个数据对比,如果第2个数据比前一个小,就先把第2个数据保存到临时变量中,然后依次往前循环,与前面的每个数据(第一次循环只有1个)作比较,如果前面的数据比临时变量大,就把前面的数据往后移1个位置(复制到后一个位置上),直到遇到比临时变量小的数据,把临时变量插入到比它小的那个数据的后面。如果对比到了下标为0的数据之后仍然没有比临时变量小的数据,就直接把临时变量插入到下标为0的位置上。用插入排序法进行逆序排序的情况下,第1次循环需要3次复制(复制出临时变量,把有序部分后移的时候也要复制,再把临时变量复制到正确的位置),第2次循环需要4次复制……第N-1次循环(因为是从第2个数据开始,所以只有N-1次)需要N+1次复制,一共(N^2+3N+3)/2次复制。如果数组中的数据是随机的,则平均需要(N^2+3N+3)/4次复制。同样,用大O表示法的时候,把常数3与3/4去掉(可以看作(N^2+3N)/4 + 3/4),再忽略掉3N,可以认为插入排序需要O(N^2)级别时间。但是一次复制与一次交换消耗的时间不同(一次交换有3次复制),所以插入排序法比冒泡排序法快得多,比选择排序略快。 
以下代码中添加了插入排序法insertionSort: 
Java代码  收藏代码
  1. package dsaa.array;  
  2. /** 
  3.  * @(#)ArrayUtil.java 2008-12-25 下午08:44:46 
  4.  *  
  5.  * @author Qiu Maoyuan 
  6.  * Array Util 
  7.  */  
  8. public class ArrayUtil {  
  9.   
  10.     public static void bubbleSort(int[] array){  
  11.         for(int i=0; i<array.length - 1; i++){  
  12.             for(int j=0; j<array.length - i - 1; j++){  
  13.                 if(array[j]>array[j + 1]){  
  14.                     swap(array, j, j + 1);  
  15.                 }  
  16.             }  
  17.         }  
  18.     }  
  19.       
  20.     public static void selectionSort(int[] array){  
  21.         for(int i=0; i<array.length - 1; i++){  
  22.             int minIndex = i;  
  23.             for(int j=i; j<array.length - 1; j++){  
  24.                 if(array[j + 1] < array[minIndex]){  
  25.                     minIndex = j + 1;  
  26.                 }  
  27.             }  
  28.             swap(array, i, minIndex);  
  29.         }  
  30.     }  
  31.       
  32.     public static void insertionSort(int[] array){  
  33.           
  34.         for(int i=1; i<array.length; i++){  
  35.             if(array[i]<array[i - 1]){  
  36.                 int temp = array[i];  
  37.                 int j = i - 1;  
  38.                 while(j>=0 && temp<array[j]){  
  39.                     array[j + 1] = array[j];  
  40.                     j--;  
  41.                 }  
  42.                 array[j + 1] = temp;  
  43.             }  
  44.         }  
  45.     }  
  46.   
  47.     private static void swap(int[] array, int index1, int index2) {  
  48.         int temp = array[index1];  
  49.         array[index1] = array[index2];  
  50.         array[index2] = temp;  
  51.     }  
  52. }  

奇偶排序法

奇偶排序法的思路是在数组中重复两趟扫描。第一趟扫描选择所有的数据项对,a[j]和a[j+1],j是奇数(j=1, 3, 5……)。如果它们的关键字的值次序颠倒,就交换它们。第二趟扫描对所有的偶数数据项进行同样的操作(j=2, 4, 6……)。重复进行这样两趟的排序直到数组全部有序。 
下面的代码是我原来的写法: 
Java代码  收藏代码
  1. public void oddEvenSort(int[] array){   
  2.     for (int i = 0; i < array.length; i += 2){   
  3.         int j = 0;  
  4.         scan(array, j);   
  5.         j = 1;  
  6.         scan(array, j);   
  7.     }   
  8. }  
  9.   
  10. private void scan(int[] array, int j) {  
  11.     while (j < array.length  - 1){   
  12.         if (array[j] > array[j + 1]){   
  13.             swap(array, j, j + 1);  
  14.         }   
  15.         j += 2;  
  16.     }  
  17. }   
  18.   
  19. private static void swap(int[] array, int index1, int index2) {  
  20.     int temp = array[index1];  
  21.     array[index1] = array[index2];  
  22.     array[index2] = temp;  
  23. }  

后来有朋友提出建议,我小小的改动了一下,对随机数组排序的效率略有提高: 
Java代码  收藏代码
  1. public static void oddEvenSort(int[] array) {  
  2.     boolean unsorted = true;  
  3.     while (unsorted) {  
  4.         unsorted = false;  
  5.         int i = 1;  
  6.         boolean oddUnsorted = scan(array, i);  
  7.         i = 0;  
  8.         boolean evenUnsorted = scan(array, i);  
  9.         unsorted = oddUnsorted || evenUnsorted;  
  10.     }  
  11. }  
  12.   
  13. private static boolean scan(int[] array, int i) {  
  14.     boolean unsorted = false;  
  15.     while (i < array.length - 1) {  
  16.         if (array[i] > array[i + 1]) {  
  17.             swap(array, i, i + 1);  
  18.             unsorted = true;  
  19.         }  
  20.         i += 2;  
  21.     }  
  22.     return unsorted;  
  23. }  
  24.   
  25. private static void swap(int[] array, int index1, int index2) {  
  26.     int temp = array[index1];  
  27.     array[index1] = array[index2];  
  28.     array[index2] = temp;  
  29. }  

附上时间测试代码: 
Java代码  收藏代码
  1. import java.util.Random;  
  2. public class ArrayUtil {      
  3.   
  4.     /** 
  5.      * 冒泡排序 
  6.      * @param array 
  7.      */  
  8.     public static <T extends Comparable<? super T>> void bubbleSort(T[] array){  
  9.         for(int i=0; i<array.length - 1; i++){  
  10.             for(int j=0; j<array.length - i - 1; j++){  
  11.                 if(array[j].compareTo(array[j + 1])>0){  
  12.                     swap(array, j, j + 1);  
  13.                 }  
  14.             }  
  15.         }  
  16.     }  
  17.       
  18.     /** 
  19.      * 选择排序 
  20.      * @param array 
  21.      */  
  22.     public static <T extends Comparable<? super T>> void selectionSort(T[] array){  
  23.         for(int i=0; i<array.length - 1; i++){  
  24.             int minIndex = i;  
  25.             for(int j=i; j<array.length - 1; j++){  
  26.                 if(array[j + 1].compareTo(array[minIndex])<0){  
  27.                     minIndex = j + 1;  
  28.                 }  
  29.             }  
  30.             swap(array, i, minIndex);  
  31.         }  
  32.     }  
  33.       
  34.     /** 
  35.      * 插入排序 
  36.      * @param array 
  37.      */  
  38.     public static <T extends Comparable<? super T>> void insertionSort(T[] array){  
  39.         for(int i=1; i<array.length; i++){  
  40.             if(array[i].compareTo(array[i - 1])<0){  
  41.                 T temp = array[i];  
  42.                 int j = i - 1;  
  43.                 while(j>=0 && temp.compareTo(array[j])<0){  
  44.                     array[j + 1] = array[j];  
  45.                     j--;  
  46.                 }  
  47.                 array[j + 1] = temp;  
  48.             }  
  49.         }  
  50.     }  
  51.       
  52.     /** 
  53.      * 奇偶排序 
  54.      * @param array 
  55.      */  
  56.     public static <T extends Comparable<? super T>> void oddEvenSort(T[] array) {  
  57.         boolean unsorted = true;  
  58.         while (unsorted) {  
  59.             unsorted = false;  
  60.             int i = 1;  
  61.             boolean oddUnsorted = scan(array, i);  
  62.             i = 0;  
  63.             boolean evenUnsorted = scan(array, i);  
  64.             unsorted = oddUnsorted || evenUnsorted;  
  65.         }  
  66.     }  
  67.   
  68.     private static <T extends Comparable<? super T>> boolean scan(T[] array, int i) {  
  69.         boolean unsorted = false;  
  70.         while (i < array.length - 1) {  
  71.             if (array[i].compareTo(array[i + 1])>0) {  
  72.                 swap(array, i, i + 1);  
  73.                 unsorted = true;  
  74.             }  
  75.             i += 2;  
  76.         }  
  77.         return unsorted;  
  78.     }  
  79.   
  80.     private static <T extends Comparable<? super T>> void swap  
  81.         (T[] array, int index1, int index2) {  
  82.         T temp = array[index1];  
  83.         array[index1] = array[index2];  
  84.         array[index2] = temp;  
  85.     }  
  86.       
  87.     /** 
  88.      * 表插入排序法 
  89.      * @param <T> 
  90.      * @param array 
  91.      */  
  92.     @SuppressWarnings("unchecked")  
  93.     public static <T extends Comparable<? super T>> void listInsertionSort(T[] array){  
  94.         SortedLinkList<?> linkList = new SortedLinkList(array);  
  95.         T[] newArray = (T[])new Comparable[array.length];  
  96.         for(int i=0; i<newArray.length; i++){  
  97.             newArray[i] = (T)linkList.remove();  
  98.         }  
  99.         array = newArray;  
  100.     }  
  101.   
  102.     public static void main(String[] args){  
  103.         Integer[] array = new Integer[10000];  
  104.         generateRandomArray(array);  
  105.         long b = System.currentTimeMillis();  
  106.         ArrayUtil.bubbleSort(array);  
  107.         long e = System.currentTimeMillis();  
  108.         System.out.println("冒泡-随机:" + (e - b)/1000.0);  
  109.           
  110.         generateContradictoryArray(array);  
  111.         b = System.currentTimeMillis();  
  112.         ArrayUtil.bubbleSort(array);  
  113.         e = System.currentTimeMillis();  
  114.         System.out.println("冒泡-逆序:" + (e - b)/1000.0);  
  115.   
  116.         generateRandomArray(array);  
  117.         b = System.currentTimeMillis();  
  118.         ArrayUtil.selectionSort(array);  
  119.         e = System.currentTimeMillis();  
  120.         System.out.println("选择-随机:" + (e - b)/1000.0);  
  121.           
  122.         generateContradictoryArray(array);  
  123.         b = System.currentTimeMillis();  
  124.         ArrayUtil.selectionSort(array);  
  125.         e = System.currentTimeMillis();  
  126.         System.out.println("选择-逆序:" + (e - b)/1000.0);  
  127.   
  128.         generateRandomArray(array);  
  129.         b = System.currentTimeMillis();  
  130.         ArrayUtil.insertionSort(array);  
  131.         e = System.currentTimeMillis();  
  132.         System.out.println("插入-随机:" + (e - b)/1000.0);  
  133.           
  134.         generateContradictoryArray(array);  
  135.         b = System.currentTimeMillis();  
  136.         ArrayUtil.insertionSort(array);  
  137.         e = System.currentTimeMillis();  
  138.         System.out.println("插入-逆序:" + (e - b)/1000.0);  
  139.   
  140.         generateRandomArray(array);  
  141.         b = System.currentTimeMillis();  
  142.         ArrayUtil.listInsertionSort(array);  
  143.         e = System.currentTimeMillis();  
  144.         System.out.println("表插入-随机:" + (e - b)/1000.0);  
  145.           
  146.         generateContradictoryArray(array);  
  147.         b = System.currentTimeMillis();  
  148.         ArrayUtil.listInsertionSort(array);  
  149.         e = System.currentTimeMillis();  
  150.         System.out.println("表插入-逆序:" + (e - b)/1000.0);  
  151.     }  
  152.   
  153.     private static void generateContradictoryArray(Integer[] array) {  
  154.         for(int i=0; i<array.length; i++){  
  155.             array[i] = array.length - i;  
  156.         }  
  157.     }  
  158.   
  159.     private static void generateRandomArray(Integer[] array) {  
  160.         Random random = new Random();  
  161.         for(int i=0; i<array.length; ){  
  162.             int item = random.nextInt(10000);  
  163.             int j;  
  164.             if(i==0) array[i]=item;  
  165.             for(j=0; j<i; ){  
  166.                 if(array[j]==item) break;  
  167.                 j++;  
  168.             }  
  169.             if(j==i){  
  170.                 array[i] = item;  
  171.                 i++;  
  172.             }  
  173.         }  
  174.     }  
  175. }  
  176.   
  177. class SortedLinkList<E extends Comparable<E>> {  
  178.   
  179.     private Link first;  
  180.   
  181.     public SortedLinkList() {  
  182.     }  
  183.   
  184.     public SortedLinkList(E[] array) {  
  185.         for (E element : array) {  
  186.             add(element);  
  187.         }  
  188.     }  
  189.   
  190.     public void add(E value) {  
  191.         Link newElement = new Link(value);  
  192.         if (isEmpty()) {  
  193.             first = newElement;  
  194.         } else {  
  195.             Link current = first;  
  196.             Link previous = null;  
  197.             while (!endOfLink(current) && current.element.compareTo(value) >= 0) {  
  198.                 previous = current;  
  199.                 current = current.next;  
  200.             }  
  201.             if (!endOfLink(current)) {  
  202.                 newElement.next = current;  
  203.             }  
  204.             if (current == first)  
  205.                 first = newElement;  
  206.             else  
  207.                 previous.next = newElement;  
  208.         }  
  209.     }  
  210.   
  211.     public E getFirst() {  
  212.         if (isEmpty())  
  213.             throw new IllegalStateException("Linklist is empty");  
  214.         return first.element;  
  215.     }  
  216.   
  217.     public boolean isEmpty() {  
  218.         return first == null;  
  219.     }  
  220.   
  221.     public E remove() {  
  222.         E value = getFirst();  
  223.         first = first.next;  
  224.         return value;  
  225.     }  
  226.   
  227.     public boolean delete(E element) {  
  228.         if (isEmpty())  
  229.             return false;  
  230.         Link current = first;  
  231.         Link previous = first;  
  232.         while (!element.equals(current.element)) {  
  233.             if (endOfLink(current.next)) {  
  234.                 return false;  
  235.             } else {  
  236.                 previous = current;  
  237.                 current = current.next;  
  238.             }  
  239.         }  
  240.         if (current == first)  
  241.             first = first.next;  
  242.         else  
  243.             previous.next = current.next;  
  244.         return true;  
  245.     }  
  246.   
  247.     private boolean endOfLink(Link link) {  
  248.         return link == null;  
  249.     }  
  250.   
  251.     @Override  
  252.     public String toString() {  
  253.         StringBuilder buffer = new StringBuilder();  
  254.         Link current = first;  
  255.         while (current != null) {  
  256.             buffer.append(current.toString());  
  257.             current = current.next;  
  258.         }  
  259.         return buffer.toString();  
  260.     }  
  261.   
  262.     private class Link {  
  263.   
  264.         private E element;  
  265.   
  266.         private Link next;  
  267.   
  268.         public Link(E element) {  
  269.             this.element = element;  
  270.         }  
  271.   
  272.         @Override  
  273.         public String toString() {  
  274.             return "[" + element.toString() + "]";  
  275.         }  
  276.     }  
  277. }  

样例代码下载:http://dl.iteye.com/topics/download/4d47aefe-4446-3c40-8048-7f039ae1d980

原创粉丝点击