1007既然说到了排序,当然有必要复习一下七大内部排序咯。。。其他的注释里面都有写,主要是要列一下效率方面。冒泡排序是当之无愧的最慢之王。。。10000条数据的排序也在500-600ms之间;选择排序200-300,插入排序300-400;快排无疑是效率最高的排序方法,时间在15-25之间;归并也不错,稳定在30ms左右;最让我吃惊的是堆排序,不知道是不是我的算法有问题,堆排序的时间一直在250-300之间徘徊;希尔排序在30-40之间。不知道有没有哪位大虾能够解释下为什么堆排序的效率如此之低。。。
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
/**
* @author kaka hu
* @time 2015年2月27日 下午10:26:11
* @description
*/
public class Main_1007_AllSorting {
public static void printArray(List<Integer> data){
for(int i=0;i<data.size();i++){
System.out.print(data.get(i)+" ");
if(i != 0 && i%1000 == 0){
System.out.println();
}
}
}
public static void swap(List<Integer> data,int i,int j){
if(i == j){
return ;
}
int temp = data.get(i);
data.set(i, data.get(j));
data.set(j, temp);
}
public static void main(String[] args) {
List<Integer> input = new ArrayList<Integer>();
for(int i=0;i<10000;i++){
input.add(new Random().nextInt(200));
}
System.out.println("排序前数组为:");
printArray(input);
//bubbleSort(input);//冒泡排序
//selectSort(input);//选择排序
//insertSort(input);//插入排序
//quickSort(input);//快速排序
//mergeSort(input);//归并排序
//heapSort(input);//堆排序
shellSort(input);//希尔排序
}
//冒泡排序,思路:从前到后,相邻的比较,较大的往后排,每轮最大的在最后
// 稳定排序(两个元素值相同,排序后不会发生相对位置变化)
// 时间复杂度最坏和平均都是O(N^2),空间复杂度1
public static void bubbleSort(List<Integer> data) {
long startTime = System.currentTimeMillis();
int length = data.size();
for(int i=length-1;i>0;i--){
for(int j=0;j<i;j++){
//相邻的两个数进行比较,冒泡
if(data.get(j) > data.get(j+1)){
swap(data,j,j+1);
}
}
}
long endTime = System.currentTimeMillis();
System.out.println("\n冒泡排序结束,用时"+(endTime-startTime)+"毫秒,排序后结果为:");
printArray(data);
}
//选择排序,思路:每次选择一个最小(大)的值,然后放到首(尾)端
// 不稳定排序,时间复杂度最坏和平均都是O(N^2),空间复杂度1
public static void selectSort(List<Integer> data){
long startTime = System.currentTimeMillis();
int length = data.size();
for(int i=0;i<length;i++){
for(int j=i;j<length;j++){
//如果比i小,找出来跟i换位
if(data.get(i) < data.get(j)){
swap(data,i,j);
}
}
}
long endTime = System.currentTimeMillis();
System.out.println("\n选择排序结束,用时"+(endTime-startTime)+"毫秒,排序后结果为:");
printArray(data);
}
//插入排序,思路:每次将要排序的数插入到已经排好序的序列中
// 稳定排序,时间复杂度最坏和平均都是O(N^2),空间复杂度1
public static void insertSort(List<Integer> data){
long startTime = System.currentTimeMillis();
int length = data.size();
for(int i=0;i<length;i++){
//待插入的数从大到小与已经排好的数进行比较
for(int j=i;j>0 && data.get(j)<data.get(j-1);j--){
swap(data,j,j-1);
}
}
long endTime = System.currentTimeMillis();
System.out.println("\n插入排序结束,用时"+(endTime-startTime)+"毫秒,排序后结果为:");
printArray(data);
}
//快速排序,思路:通过一趟扫描,就能确保某个数(一般为第一个数)的左边各数都比它小,右边各数都比它大,然后进行递归。
// 不稳定排序,时间复杂度最坏是O(N^2),平均是O(N*log2N),空间复杂度为1
public static void quickSort(List<Integer> data){
long startTime = System.currentTimeMillis();
int length = data.size();
quickSortRecursion(data,0,length-1);
long endTime = System.currentTimeMillis();
System.out.println("\n快速排序结束,用时"+(endTime-startTime)+"毫秒,排序后结果为:");
printArray(data);
}
//快排的递归
public static void quickSortRecursion(List<Integer> data,int low,int high){
if(low < high){
int temp = data.get(low);//基准数
int i=low;
int j=high;
while(i < j){
while(i < j && data.get(j) >= temp){//先从右边开始,找到第一个比基准数小的
j--;
}
data.set(i, data.get(j));//交换位置
while(i < j && data.get(i) <= temp){//再从左边开始,找到第一个比基准数大的
i++;
}
data.set(j, data.get(i));//交换位置
}//依次循环,直到基准数左边都比它小,右边都比它大
data.set(i, temp);
quickSortRecursion(data,low,i-1);
quickSortRecursion(data,i+1,high);
}
}
//归并排序,思路:一般为二路归并,将数据分组直到最小集,然后进行两两归并
// 稳定排序,时间复杂度最坏和平均都是O(N*log2N),空间复杂度为O(N)(需要额外的数组)
public static void mergeSort(List<Integer> data){
long startTime = System.currentTimeMillis();
int length = data.size();
mergeSortRecursion(data,0,length-1);
long endTime = System.currentTimeMillis();
System.out.println("\n归并排序结束,用时"+(endTime-startTime)+"毫秒,排序后结果为:");
printArray(data);
}
//归并排序的递归,首先进行一步一步的递归分解,直到最小2个数
public static void mergeSortRecursion(List<Integer> data,int low,int high){
if(low < high){
int mid = (low+high)/2;
mergeSortRecursion(data,low,mid);
mergeSortRecursion(data,mid+1,high);
merge(data,low,high);
}
}
//归并排序的归并,已经排序好的两个数组进行归并
public static void merge(List<Integer> data,int low,int high){
List<Integer> temp = new ArrayList<Integer>();
int mid = (low+high)/2;
int i=low;
int j=mid+1;
//low到mid,mid+1到high为两个已经排好序的数组
while(i<=mid && j<=high){
//谁小就加谁,然后移位
if(data.get(i) <= data.get(j)){
temp.add(data.get(i));
i++;
}else{
temp.add(data.get(j));
j++;
}
}
//有一组移位完毕,直接把另外一组加入即可
while(i <= mid){
temp.add(data.get(i));
i++;
}
while(j <= high){
temp.add(data.get(j));
j++;
}
//复制数组
for(int p=0;p<=high-low;p++){
data.set(low+p, temp.get(p));
}
temp = null;
}
//堆排序,思路:构建大根堆,保证每个节点都比左右子节点要大,然后交换第一个和最后一个节点,继续构建除最后一个节点外的大根堆
// 不稳定排序,时间复杂度最坏和平均都是O(N*log2N),空间复杂度为O(1)
public static void heapSort(List<Integer> data){
long startTime = System.currentTimeMillis();
int length = data.size();
for(int i=0;i<length-1;i++){
createMaxHeap(data,length-1-i);
swap(data,0,length-1-i);
}
long endTime = System.currentTimeMillis();
System.out.println("\n堆排序结束,用时"+(endTime-startTime)+"毫秒,排序后结果为:");
printArray(data);
}
//构建大根堆,从最后一个有子节点的节点开始,保证每个节点都比左右子节点要大,否则交换
public static void createMaxHeap(List<Integer> data,int maxIndex){
for(int i=(maxIndex-1)/2;i>=0;i--){
int max = 2*i+1;//左子节点
//如果右子节点存在
if(2*i+2 <= maxIndex && data.get(max) < data.get(2*i+2)){
max = 2*i+2;
}
if(data.get(i) < data.get(max)){
swap(data,i,max);
}
}
}
//希尔排序,思路:将数组分为n组,分别插入排序,然后依次扩大分组,知道整个数组有序
// 不稳定排序,平均时间N*log2N,空间复杂度O(1)
public static void shellSort(List<Integer> data){
long startTime = System.currentTimeMillis();
int length = data.size();
int count = length/2;
while(count >= 1){
for(int i=count;i<length;i++){
int temp = data.get(i);
int j;
for(j=i;j>=count && data.get(j-count)>temp;j=j-count){
data.set(j, data.get(j-count));
}
data.set(j, temp);
}
count = count/2;
}
long endTime = System.currentTimeMillis();
System.out.println("\n希尔排序结束,用时"+(endTime-startTime)+"毫秒,排序后结果为:");
printArray(data);
}
}