排序
//工具类
package shujujiegou.sort;
import java.util.Random;
public class methodClass {
//输出排序前和排序后的数组,并加以分离
public static void print(int a[],Sort sort){
System.out.print("排序前 :");
print(a);
sort.Sort(a);
System.out.println();
System.out.print("排序后 :");
print(a);
System.out.println();
}
//格式化输出
public static void print(int a[]){
for (int i = 0; i < a.length; i++) {
System.out.format("%3d", a[i]);
}
}
// 自动生成数组方法
public static int[] random(int i) {
Random ra = new Random();
int a[] = new int[i];
for (int j = 0; j < a.length; j++) {
a[j] = ra.nextInt(100); //100以内的数
}
return a;
}
}
package shujujiegou.sort;
//基类
public abstract class Sort {
public abstract void Sort(int a[]);
//制定随机数组多少个元素
void Sort(int num) {
System.out.println("************"+this.getClass().getSimpleName()+"************");
methodClass.print(methodClass.random(num), this);
}
//默认10个元素
public void Sort() {
System.out.println("************"+this.getClass().getSimpleName()+"************");
;
methodClass.print( methodClass.random(10), this);
}
//制定排序数组
public void sortWithArray(int a[]) {
System.out.println("************"+this.getClass().getSimpleName()+"************");
methodClass.print(a, this);
}
}
直接插入排序
package shujujiegou.sort.method;
import shujujiegou.sort.Sort;
public class insertSort extends Sort{
@Override
public void Sort(int[] a) {
/*
* 基本思想 对前2、3、4、5、6、n-1 个数分别进行排序
* 排序一趟,前n-1个就已经排序好,只需找到要将第N个数插入的位置
* 对于一个数组 a[]={a1,a2,a3,a4,a5,a6,a7,a8,a9};
* a[]={ 9, 8, 7, 6, 5, 4, 3, 2, 1};
* 我们进行a.length-1次排序
* 先把第一个元素当做是已排序的,
* 再排序前两元素
* 然后前三个
*
* 例如第3个元素
* 假设数组为 231
* 进行这样的交换
* 如果3>1 则 1=3
* 如果 2>1 则 3=2
* 最后 将 2=1
* 也就是说让
* a[i+1]=a[i]
*
* 保证两点:
* 1、取一个关键元素
* 2、找到他所插入的位置
*/
for (int i = 1; i < a.length; i++) {//外层n-1趟
int temp = a[i], j;//存储要插入的数的值和下标
for (j = i - 1; j >= 0 && temp < a[j]; j--) {
a[j + 1] = a[j];
}//这个for循环是找到 插入的数的位置
a[j + 1] = temp;
/*
* System.out.println("第" + i + "趟"); print(table);
* System.out.println();
*/
}
}
}
希尔(缩小量)排序(Shell's Sort)
package shujujiegou.sort.method;
import shujujiegou.sort.Sort;
public class shellSort extends Sort {
@Override
/*
* 希尔排序,缩小量排序 (non-Javadoc)
*
* 此时会分元组个数为奇数还是偶数,
* 偶数 平均两两配对
* 例如 a1 a2 a3 a4 a5 a6
* a1 a4
* a2 a5
* a3 a6
* 这样正好3对,j-=delta 不会多出
* 而如果是奇数
* 例如 a1 a2 a3 a4 a5
* a1 a3
* a2 a4
* a3 a5
* a1 a3
* 这里指的都是下标 就会分成四对
*
* 而且当第二次分组后 ,并不是一组一组来进行直接排序的
* 而是这样
* 例如 a1 a2 a3 a4 a5 a6 a7 a8
* 分组为 a1 a3 a5 a7
* a2 a4 a6 a8
* 此时最内层排序时
* 是先选择 a1 a3 a5 a7 这一组的 a1 a3
* 然后排序 a2 a4 a6 a8 这一组的a2 a8
* 再进行 a1 a3 a5 的排序
* 然后 a2 a4 a6的排序
*
* 不是一组一组来的, 这和定义有很大出入 (不过透明上看做是 一组一组来的)
* 但还是有分组的思想在里面的
*
*
* @see shujujiegou.sort.Sort#Sort(int[])
*/
public void Sort(int[] table) {
for (int delta = table.length / 2; delta > 0; delta /= 2) {
for (int i = delta; i < table.length; i++) {
int temp = table[i], j;
for (j = i - delta; j >= 0 && temp < table[j]; j -= delta) {
table[j + delta] = table[j];
}
table[j + delta] = temp;
}
System.out.println("外层");
}
}
}
因为是交换的排序,分了组,所以肯定不稳定
冒泡排序
package shujujiegou.sort.method;
import shujujiegou.sort.Sort;
public class bubbleSort extends Sort {
@Override
public void Sort(int[] table) {
// TODO Auto-generated method stub
boolean exchange = true;
/*
* 这个算法是从看元素的大小位置,如果不符合策略,就交换位置
* 而对外表现为 一次排序 一个元素到达了合适位置
* 因此如果有元素没有发生交换就 可以停止交换了
*
* 它的核心思想是,查看相邻元素大小,不符合策略,交换
* 因为是 相邻交换,所以它也是稳定的,不会打乱元素的相对位置
*/
for (int i = 1; i < table.length && exchange; i++) {
exchange = false;
int temp ;
for (int j = 0; j < table.length - i; j++) {
if (table[j] > table[j + 1]) {
exchange = true;
temp = table[j];
table[j] = table[j + 1];
table[j + 1] = temp;
}
}
}
}
/*
* 这也算是一种冒泡排序
* 有直接插入排序和冒泡的思想
*
* 利用直接插入排序的 分别排序 前N个元素, 使子序列一直是排序的
* 而未排序的下一个元素 则按照真正的冒泡来 选择到合适的位置,
*
* a1 a2 a3 a4 a5
* a1 有序
* a2 冒泡
* a1 a2 有序
* a3冒泡
* a1 a2 a3 有序
* a4冒泡
*/
public void Sort2(int[] a ) {
for (int i = 1; i < a.length; i++) {
for (int j = i-1; j>=0&&a[j+1]<a[j]; j--) {
int temp=a[j+1];
a[j+1]=a[j];
a[j]=temp;
}
}
}
}
快速排序
package shujujiegou.sort.method;
import shujujiegou.sort.Sort;
public class quickSort extends Sort {
@Override
/*
* 选一个关键字 数组元素中<它扔前面,>它扔后面
* 然后再在这两个子序列中选择关键字 ,重复上述操作
* (non-Javadoc)
* @see shujujiegou.sort.Sort#Sort(int[])
*/
public void Sort(int[] a) {
Sort(a, 0, a.length-1);
}
//重载方法, 为了使用递归,和让用户直接使用带一个数组参数的快速排序方法
public void Sort(int a[],int begin,int end){
if(begin<end){ //验证合法
int i=begin,j=end,vot=a[i];// i j vot 存储值 而且将数组的第一个元素作为基准
while(i!=j){//当i和j不相等时证明 元素未移动完成
//先找小的元素
while(i<j&&a[j]>=vot){ //从后往前找, 如果最后一个元素是大于基准的,不用动,让j--,找下一个,直到a[j]<=vot为止
j--;
}
//找到小的元素了, 开始移动 ,往空的下标填
//空的下标当然要往i可能的范围填, 开始当然是第一个元素,然后将i+1,将空位移到下一个元素
if(i<j){
a[i++]=a[j]; //这里是i++, i是后加的 ,要让找出来的小于关键字的a[j] 去占空位
}
// 找大的元素
while(i<j&&a[j]<=vot){ //从前往后找, 如果第一个元素是小于基准的,不用动,让i++,找下一个,直到a[j]>=vot为止
i++;
}
//找到小的元素了, 开始移动 ,往空的下标填
//空的下标当然要往j可能的范围填,刚开始当然是移动到前面的空的j了,然后将j移到下一个空的
if(i<j){
a[j--]=a[i]; //这里是j--, j是后减的,要让找出来的大于关键字的 a[i]去占空位
}
}
a[i]=vot; // 基准值到达最后位置 也可以写成 a[j]=vot
//递归调用
Sort(a, begin, j-1); //前端排序,
Sort(a,i+1, end);//后端排序
}
}
/*
*
*
*
* 因为它随意的交换的元素之间的关系, 所以是不稳等的
*/
}
选择排序
package shujujiegou.sort.method;
import shujujiegou.sort.Sort;
public class selectSort extends Sort {
@Override
/*
* 基本思想: 选择数组中最小的 放在第1位, 然后再选 放在第2位 这样前N个始终是排序好的 (non-Javadoc)
* 只有一点可以值得说说
*
* 就是求最大值下标和求最大值
* 最大值下标核心
* if(a[j]<a[min]){
min=j;
}
*最大值核心
*if(max<a[j]){
*max=a[j];
*}
*
*还不如求到下标后 return array[min]
* 也是不稳定的
* @see shujujiegou.sort.Sort#Sort(int[])
*/
public void Sort(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
int min = i;
for (int j = i + 1; j < a.length; j++) {
if(a[j]<a[min]){
min=j;
}
}
int temp=a[min];
a[min]=a[i];
a[i]=temp;
}
}
}
归并排序
感觉好难的额,
package shujujiegou.sort.method;
import shujujiegou.sort.Sort;
import shujujiegou.sort.main;
public class mergeSort extends Sort {
/*
* 我还是感觉比较难得 一个方法理解了好长时间, 其原理就是将两个已经排序的子数组归并成一个 , 再往下细分, 就是将一个数组 分为两个元素一组,
* 然后进行归并 核心方法是 merge() , 归并方法 (non-Javadoc)
*
*
* 这个算法好难, 他以空间换时间了,
* 是稳定的
* @see shujujiegou.sort.Sort#Sort(int[])
*/
@Override
public void Sort(int[] a) {
mergeSort(a);
}
/*
* 核心方法merge 原理是这样 m r-1 r r+n-1 X数组为 5 7 9 11 12 1 3 10 15 i j Y数组为 1 3 5 7
* 9 10 11 12 15 为辅助数组 k 5 1比较1放Y中,j++,K++,i不变 5 3比较3放Y中,j++,k++,i不变 5
* 10比较5放Y中,i++,k++,j不变 这样下去直到 两个子序列 其中一个到达尾部 再将剩下的归并到Y中就可以了
*/
private void merge(int X[], int Y[], int m, int r, int n) {
int i = m, j = r, k = m;
while (i < r && j < r + n && j < X.length) { // 将X中的两个相邻子序列归并到Y中
if (X[i] < X[j]) {// 选择较小的值
Y[k++] = X[i++];
} else {
Y[k++] = X[j++]; // 看不懂看上面
}
}
// 将前一个子序列剩余元素复制到Y中
while (i < r) {
Y[k++] = X[i++];
}
while (j < r + n && j < X.length) {
Y[k++] = X[j++];
}
}
private void mergePass(int X[], int Y[], int n) {
int i = 0;
while (i < X.length - 2 * n + 1) { // 不明白 ,为什么不可以写成 i<X.length/2
merge(X, Y, i, i + n, n); // 一个一个归并 如 a1 a2 a3 a4 a5 a6 a7
// a1 a2 归并 a3 a4归并 a5 a6 归并 a7先留下来
i += 2 * n;
}
if (i + n < X.length) {
merge(X, Y, i, i + n, n); // 还有可以配对的两个元素,再一次归并排序
} else {
for (int j = i; j < X.length; j++) { // 将X的剩余元素复制到Y中
Y[j] = X[j];
}
}
}
// 归并总排序
private void mergeSort(int X[]) {
int[] Y = new int[X.length];
int n = 1;
while (n < X.length) {
mergePass(X, Y, n);
n *= 2; // 2个归并 4 个归并 ---------------
if (n < X.length) {
mergePass(Y, X, n); // 将Y再归并至X中
}
}
}
}
排序法 | 平均时间 | 最差情形 | 稳定度 | 额外空间 | 备注 |
冒泡 | O(n2) | O(n2) | 稳定 | O(1) | n小时较好 |
交换 | O(n2) | O(n2) | 不稳定 | O(1) | n小时较好 |
选择 | O(n2) | O(n2) | 不稳定 | O(1) | n小时较好 |
插入 | O(n2) | O(n2) | 稳定 | O(1) | 大部分已排序时较好 |
基数 | O(logRB) | O(logRB) | 稳定 | O(n) | B是真数(0-9),R是基数(个十百) |
Shell | O(nlogn) | O(ns) 1<s<2 | 不稳定 | O(1) | s是所选分组 |
快速 | O(nlogn) | O(n2) | 不稳定 | O(nlogn) | n大时较好 |
归并 | O(nlogn) | O(nlogn) | 稳定 | O(1) | n大时较好 |
堆 | O(nlogn) | O(nlogn) | 不稳定 | O(1) | n大时较好 |
http://blog.csdn.net/iamfranter/article/details/6825207
明天看 来完善自己的博客