7-12 排序(25 分)
给定N个(长整型范围内的)整数,要求输出从小到大排序后的结果。
本题旨在测试各种不同的排序算法在各种数据情况下的表现。各组测试数据特点如下:
- 数据1:只有1个元素;
- 数据2:11个不相同的整数,测试基本正确性;
- 数据3:103个随机整数;
- 数据4:104个随机整数;
- 数据5:105个随机整数;
- 数据6:105个顺序整数;
- 数据7:105个逆序整数;
- 数据8:105个基本有序的整数;
- 数据9:105个随机正整数,每个数字不超过1000。
-
输入格式:
输入第一行给出正整数N(≤105),随后一行给出N个(长整型范围内的)整数,其间以空格分隔。
输出格式:
在一行中输出从小到大排序后的结果,数字间以1个空格分隔,行末不得有多余空格。
输入样例:
11 4 981 10 -17 0 -20 29 50 8 43 -5
输出样例:
-20 -17 -5 0 4 8 10 29 43 50 981
思路:
1、各种排序算法适用的场景不同,但是优化后的排序明显比简单排序快的多。堆排序和归并排序好就好在,受数据的影响很小,即使在最差的情况下,时间也差不多。
2、堆排序,特别适用于从一个大量数据中找出顺序找出最大(小)的一部分。例如,从10000个数中按从小到大找出最大的100个数。
3、这里补充一点建堆的结论。自顶向下建堆,时间复杂度是O(NlogN),自下向上(每个节点向下过滤)建堆时间复杂度是O(N).
单位/ms | 冒泡排序 | 插入排序 | 希尔排序sedgewick | 堆排序 | 归并排序 |
只有一个元素 | 155 | 103 | 102 | 93 | 95 |
11个不相同整数 | 161 | 99 | 94 | 92 | 90 |
10^3个随机整数 | 200 | 162 | 141 | 140 | 136 |
10^4个随机整数 | 647 | 384 | 401 | 377 | 375 |
10^5个随机整数 | 超时 | 2639 | 1081 | 999 | 958 |
10^5个顺序整数 | 1464 | 1024 | 1096 | 1022 | 1010 |
10^5个逆序整数 | 超时 | 3843 | 959 | 1042 | 1024 |
10^5个基本有序的整数 | 2090 | 1081 | 898 | 1057 | 1045 |
10^5个随机正整数,每个数字不超过1000 | 超时 | 2388 | 957 | 997 | 978 |
时间复杂度 | O(N^2) | O(N^2) | O(N^3/2) | O(NlogN) | O(NlogN) |
是否需要额外空间 | 否 | 否 | 否 | 否 | N |
稳定性 | 稳定 | 稳定 | 不稳定 | 不稳定 | 稳定 |
import java.io.IOException;
import java.io.StreamTokenizer;
import java.io.InputStreamReader;
import java.io.BufferedReader;
public class Main {
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
StreamTokenizer in = new StreamTokenizer(new BufferedReader(new InputStreamReader(System.in)));
in.nextToken();
int n = (int) in.nval;
int a [] = new int[n];
for(int i = 0;i<n;i++) {
in.nextToken();
a[i] = (int) in.nval;
}
// bubble_sort(a,n);
// insert_sort(a,n);
// shell_sort(a,n);
heap_sort(a, n);
// merge_sort(a,n);
print(a,n);
}
private static void print(int[] a,int n ) { //打印结果
// TODO Auto-generated method stub
int flag=0;
for(int i =0;i<n;i++) {
if(flag !=0)
System.out.print(" ");
System.out.print(a[i]);
flag =1;
}
}
private static void bubble_sort(int[] a, int n) { //冒泡排序
// TODO Auto-generated method stub
int temp;
int flag =0;
for(int i = 0;i<n-1;i++) {
for(int j = 0;j<n-i-1;j++) {
if(a[j]>a[j+1]) {
temp = a[j];
a[j] = a[j+1];
a[j+1] = temp;
flag =1;
}
}
if(flag ==0)
break;
flag =0;
}
}
private static void insert_sort(int a[],int n) { //插入排序
int j;
for(int i =1;i<n;i++) {
int tmp = a[i];
for( j =i-1;j>=0&&a[j]>tmp;j--) {
a[j+1]=a[j];
}
a[j+1] = tmp;
}
}
private static void shell_sort(int[] a, int n) { // 希尔排序
// TODO Auto-generated method stub
Stack<Integer> st = sedgewick(n);
while (!st.isEmpty()) {
int i = st.pop();
// System.out.println(i);
for (int j = 0; j < i; j++) {
for (int k = j + i; k < n; k += i) {
int temp = a[k], p;
for (p = k - i; p >= 0 && a[p] > temp; p -= i)
a[p + i] = a[p];
a[p + i] = temp;
}
}
}
}
private static Stack<Integer> sedgewick(int n) {
// TODO Auto-generated method stub
Stack<Integer> st = new Stack<>();
int i = 0, j = 2, s;
do {
int s1 = (int) (9 * Math.pow(4, i) - 9 * Math.pow(2, i)) + 1;
int s2 = (int) (Math.pow(4, j) - 3 * Math.pow(2, j) + 1);
if (s1 > s2) {
s = s2;
j++;
} else {
s = s1;
i++;
}
st.push(s);
} while (st.peek() < n);
st.pop();
return st;
}
private static void heap_sort(int[] a, int n) { //堆排序
int tmp,child,parent;
for(int i = n/2-1;i>=0;i--) {
tmp =a[i];
for(parent =i;2*parent+1<n;parent =child) {
child = 2*parent+1;
if(child<n-1&&a[child]<a[child+1])
child++;
if(tmp>=a[child])
break;
else
a[parent] = a[child];
}
a[parent] = tmp;
}
for(int i=n-1;i>0;i--) {
tmp =a[0];
a[0] = a[i];
a[i] = tmp;
tmp =a[0];
for(parent =0;2*parent+1<i;parent =child) {
child =2*parent+1;
if(child<i-1&&a[child]<a[child+1])
child++;
if(tmp>a[child])
break;
else
a[parent] = a[child];
}
a[parent] = tmp;
}
}
private static void merge_sort(int a[],int n) { //归并排序
int temp [] = new int[n];
int length=1;
while(length<n) {
merge_pass(a,temp,length,n);
length*=2;
merge_pass(temp,a,length,n);
length*=2;
}
}
private static void merge_pass(int[] a, int temp[],int length, int n) {
int i;
// TODO Auto-generated method stub
for( i =0;i<=n-2*length;i+=2*length) {
merge(a,temp,i,i+length,i+2*length-1);
}
if(n-i>length)
merge(a,temp,i,i+length,n-1);
else
for(int k =i;k<n;k++) {
temp[k] =a[k];
}
}
private static void merge(int[] a, int[] temp, int L, int R, int right_end) {
// TODO Auto-generated method stub
int left_end =R-1;
int k =L ;
int num = right_end-L+1;
while(L<=left_end&&R<=right_end) {
if(a[L]<=a[R]) {
temp[k] = a[L];
k++;L++;
}
else {
temp[k] = a[R];
k++;R++;
}
}
while(L<=left_end) {
temp[k] =a[L];
k++;
L++;
}
while(R<=right_end) {
temp[k] =a[R];
k++;
R++;
}
for(int i =k-1,j =0 ;j<num;j++,i--) {
a[i] = temp[i];
}
}
}