长度为N的数组升序排序
一,冒泡排序
public class BubbleSort { public void sort(int[] data){ for(int p = data.length - 1 ; p > 0 ; p--){ for(int i = 0 ; i < p ; i++){ if(data[i] > data[i+1] ){ int tmp = data[i]; data[i] = data[i+1]; data[i+1] = tmp; } } } this.display(data); } private void display(int[] data){ for(int i : data){ System.out.print(i+" "); } } public static void main(String[] args) { int[] data = {6, 5, 4, 3, 2, 1}; BubbleSort bs = new BubbleSort(); bs.sort(data); } }
比较次数:
第一次需比较N-1次,第二次需比较N-2次......,总比较次数为(N-1) + (N-2) +...+ 1 = N*(N-1)/2
交换次数:
如果待排序数组为逆序,则需交换N*(N-1)/2次,如果待排序数组为顺序,则不需要进行交换,对于乱序数组,平均需要交换N*(N-1)/4次
时间复杂度:
N*(N-1)/2 + N*(N-1)/4,O(N*N)
二,选择排序
public class SelectSort { public void sort(int[] data){ for(int i = 0 ; i < data.length - 1 ; i++){ int flag = i; for(int j = i + 1 ; j <= data.length - 1 ; j++){ if(data[j] < data[flag]){ flag = j; } } int tmp = data[i]; data[i] = data[flag]; data[flag] = tmp; } this.display(data); } public void display(int[] data){ for(int i : data){ System.out.print(i + " "); } } public static void main(String[] args) { int[] data = {6, 5, 4, 3, 2, 1}; SelectSort selectSort = new SelectSort(); selectSort.sort(data); } }
比较次数:
第一次需比较N-1次,第二次需比较N-2次......,总比较次数为(N-1) + (N-2) +...+ 1 = N*(N-1)/2
交换次数:
如果待排序数组为逆序,则需交换N次,如果待排序数组为顺序,则不需要进行交换,则对于乱序数组,平均需要交换N/2次
时间复杂度:
N*(N-1)/2 + N/2,O(N*N),由于交换次数比冒泡排序少,因此会比冒泡排序快
三,插入排序:插入排序特别适合用来处理局部有序的数据
public class InsertSort { public void sort(int[] data){ for(int i = 1 ; i < data.length ; i++){ int tmp = data[i]; int insertPoint = i; while(insertPoint > 0 && data[insertPoint-1] > tmp){ data[insertPoint] = data[insertPoint-1]; insertPoint -= 1; } if(insertPoint < i){ data[insertPoint] = tmp; } } this.display(data); } public void display(int[] data){ for(int i : data){ System.out.print(i + " "); } } public static void main(String[] args) { int[] data = {1, 2, 3, 6, 5, 4}; InsertSort insertSort = new InsertSort(); insertSort.sort(data); } }
比较次数:
如果带排序数组为逆序,则第一次需比较1次,第二次需比较2次......,总比较次数为1+2+...+(N-1)=N*(N-1)/2,所以在最差情况下(逆序),插入排序的比较次数和冒泡排序、选择排序是一样的,实际上每一趟排序发现插入点之前,平均只有一半的数据(待排序数组为乱序)进行了比较,所以合理的比较次数应该为:N*(N-1)/4,值得注意的是,如果待排序数据为局部有序的,则比较次数将减少很多
交换次数(需要考虑数据项移动的问题):
交换次数小于比较次数
时间复杂度:
N*(N-1)/4 + N*(N-1)/4,O(N*N)
如果数组是基本有序的,即每个数据项只需移动1次或不需要移动,那么插入排序的时间复杂度将变为O(N),这无疑是非常快的
四,表排序:
主要是利用了有序单链表的特性(当然也可以使用二叉搜索树等等),将数组中的所有数据插入到有序链表中,它们将自动按顺序排列,然后再顺次取出链表中的所有数据,把它们放到数组中,数组便排好序了
public class SortedList { private final class Node{ private int num; private Node next = null; Node(int num){ this.num = num; } } private Node first = null; public void insert(int num){ Node node = new Node(num); if(first == null){ first = node; }else{ if(node.num < first.num){ node.next = first; first = node; }else{ Node pre = first; Node cur = first.next; while(cur != null && (node.num > cur.num)){ pre = cur; cur = cur.next; } pre.next = node; node.next = cur; } } } public int deleteFirst() throws Exception{ if(first == null) throw new Exception("empty!"); Node temp = first; first = first.next; return temp.num; } }
public class ListSort { public void sort(int[] data) throws Exception{ SortedList sl = new SortedList(); for(int num : data){ sl.insert(num); } for(int i = 0 ; i< data.length ; i++){ data[i] = sl.deleteFirst(); } this.display(data); } public void display(int[] data){ for(int i : data){ System.out.print(i + " "); } } public static void main(String[] args) throws Exception{ int[] data = {6, 5, 4, 3, 2, 1}; ListSort ls = new ListSort(); ls.sort(data); } }
比较次数:
将数据项插入链表平均需要比较N/2次
移动次数:
将数组数据项放入链表,再将链表数据项放回数组,总共需移动2N次
时间复杂度:
N/2 + 2N,O(N)
虽然排序速度比上面3种排序方式要快,但是需要大约2倍的内存空间,典型的空间换时间