基本排序

目录

冒泡排序

选择排序

插入排序

表排序


长度为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 =  \frac{(N-1+1)\times (N-1)}{2} = \frac{N\times (N-1))}{2}

交换次数:

如果待排序数组为逆序,交换次数等于比较次数

时间复杂度:

\frac{N\times (N-1))}{2} + \frac{N\times (N-1))}{2}​​​​​​​ = O(N^{2})

 

选择排序

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 =  \frac{(N-1+1)\times (N-1)}{2} = \frac{N\times (N-1))}{2}

交换次数:

如果待排序数组为逆序,则需交换N-1次

时间复杂度:

\frac{N\times (N-1))}{2} + N -1 = O(N^{2})​​​​​​​,由于交换次数比冒泡排序少,因此会比冒泡排序快

 

插入排序

插入排序特别适合用来处理局部有序的数据

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倍的内存空间,典型的空间换时间

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值