排序算法

插入排序
特点:stable sort、In-place sort
最优复杂度:当输入数组就是排好序的时候,复杂度为O(n),而快速排序在这种情况下会产生O(n^2)的复杂度。
最差复杂度:当输入数组为倒序时,复杂度为O(n^2)
插入排序比较适合用于“少量元素的数组”。
其实插入排序的复杂度和逆序对的个数一样,当数组倒序时,逆序对的个数为n(n-1)/2,因此插入排序复杂度为O(n^2)。
递归版插入排序
冒泡排序
特点:stable sort、In-place sort
思想:通过两两交换,像水中的泡泡一样,小的先冒出来,大的后冒出来。
最坏运行时间:O(n^2)
最佳运行时间:O(n^2)(当然,也可以进行改进使得最佳运行时间为O(n))
递归版冒泡排序
 
 
 
 
 
 
 
 
选择排序
特性:In-place sort,unstable sort。
思想:每次找一个最小值。
最好情况时间:O(n^2)。
最坏情况时间:O(n^2)
 
递归版选择排序
 
 
 
归并排序
特点:stable sort、Out-place sort
思想:运用分治法思想解决排序问题。
最坏情况运行时间:O(nlgn)
最佳运行时间:O(nlgn)
快速排序
特性:unstable sort、In-place sort。
最坏运行时间:当输入数组已排序时,时间为O(n^2),当然可以通过随机化来改进(shuffle array 或者 randomized select pivot),使得期望运行时间为O(nlgn)。
最佳运行时间:O(nlgn)
 
 
 
 
 
 
 
堆排序
特性:unstable sort、In-place sort。
最优时间:O(nlgn)
最差时间:O(nlgn)
 
 
 
 
 
 
 
 
计数排序
特性:stable sort、out-place sort。
最坏情况运行时间:O(n+k)
最好情况运行时间:O(n+k)
 
 
 
 
 
 
 
 
 
基数排序
特性:stable sort、Out-place sort。
最坏情况运行时间:O((n+k)d)
最好情况运行时间:O((n+k)d)
桶排序
特性:out-place sort、stable sort。
最坏情况运行时间:当分布不均匀时,全部元素都分到一个桶中,则O(n^2),当然[算法导论8.4-2]也可以将插入排序换成堆排序、快速排序等,这样最坏情况就是O(nlgn)。
最好情况运行时间:O(n)
 
 
 
 
public class BubbleSort {
public static void main(String[] args) {
int num[] = {7,3,5,4,1123,6,8,5};
new BubbleSort().sort(num);
for (int n : num) {
System.out.print(n + " ");
}

//Dictionary<String, Integer> dictionary = new Hashtable<>();
}
void sort(int num[]){
int Length= num.length;
for(int i=0;i<Length-1;i++){
for(int j=0;j<Length-i-1;j++){
if(num[j]>num[j+1]){
Utils.exec(num, j, j+1);
}
}
}
}

}



1.将待排数据按一个映射函数f(x)分为连续的若干段。理论上最佳的分段方法应该使数据平均分布;实际上,通常采用的方法都做不到这一点。显然,对于一个已知输入范围在【0,10000】的数组,最简单的分段方法莫过于x/m这种方法,例如,f(x)=x/100。
“连续的”这个条件非常重要,它是后面数据按顺序输出的理论保证。
2.分配足够的桶,按照f(x)从数组起始处向后扫描,并把数据放到合适的桶中。对于上面的例子,如果数据有10000个,则我们需要分配101个桶(因为要考虑边界条件:f(x)=x/100会产生【0,100】共101种情况),理想情况下,每个桶有大约100个数据。
3.对每个桶进行内部排序,例如,使用快速排序。注意,如果数据足够大,这里可以继续递归使用桶排序,直到数据大小降到合适的范围。
4.按顺序从每个桶输出数据。例如,1号桶【112,123,145,189】,2号桶【234,235,250,250】,3号桶【361】,则输出序列为【112,123,145,189,234,235,250,250,361】。
*/
public class BucketSort {
/**
* 桶排序算法,对arr进行桶排序,排序结果仍放在arr中
* @param arr
*/
static void bucketSort(double arr[]){
int n = arr.length;
ArrayList arrList[] = new ArrayList [n];
//把arr中的数均匀的的分布到[0,1)上,每个桶是一个list,存放落在此桶上的元素
for(int i =0;i<n;i++){
int temp = (int) Math.floor(n*arr[i]);
if(null==arrList[temp])
arrList[temp] = new ArrayList();
arrList[temp].add(arr[i]);
}
//对每个桶中的数进行插入排序
for(int i = 0;i<n;i++){
if(null!=arrList[i])
insert(arrList[i]);
}
//把各个桶的排序结果合并
int count = 0;
for(int i = 0;i<n;i++){
if(null!=arrList[i]){
Iterator iter = arrList[i].iterator();
while(iter.hasNext()){
Double d = (Double)iter.next();
arr[count] = d;
count++;
}
}
}
}
/**
* 用插入排序对每个桶进行排序
* @param list
*/
static void insert(ArrayList list){
if(list.size()>1){
for(int i =1;i<list.size();i++){
if((Double)list.get(i)<(Double)list.get(i-1)){
double temp = (Double) list.get(i);
int j = i-1;
for(;j>=0&&((Double)list.get(j)>(Double)list.get(j+1));j--)
list.set(j+1, list.get(j));
list.set(j+1, temp);
}
}
}
}
/**
* 测试.....
* 这里的测试数据是一个含n个元素的数组,且每个元素满足0<=arr[i]<1
*/
public static void main(String[] args) {
double arr[] = {0.78,0.17,0.39,0.26,0.72,0.94,0.21,0.12,0.23,0.68};
bucketSort(arr);
for(int i = 0;i<arr.length;i++)
System.out.println(arr[i]);
}
}

public class CountingSort {

public static void main(String[] args) {

//首位加0,同步伪代码
int[] A = {8,3,5,1,2,7,4,3,2,1,6,7,2,0};
System.out.println("排序前:");
for(int i:A) {
System.out.print(i + " ");
}
System.out.println("\n排序后:");
CountingSort countingSort = new CountingSort();
int[] B = countingSort.sort(A);
for(int i:B) {
System.out.print(i + " ");
}
}


/**
* 计数排序实现,注意这里的实现和伪代码不同的是,数组是从0开始的
*
* @param A
*/
public int[] sort(int[] A) {
int k = findMax(A);
int[] C = new int[k+1]; //长度加1,同步伪代码
int[] B = new int[A.length];

//初始化
for(int i=0;i<C.length;i++) {
C[i] = 0;
}
//将带排序数组元素重复个数映射到辅助数组中
for(int i=0;i < A.length;i++) {
C[A[i]] = C[A[i]] + 1;
}
//处理辅助数组,使c[j]表示待排序数组中小于等于j的元素个数
for(int i=1;i<C.length;i++) {
C[i] = C[i] + C[i-1];
}
//从后往前还原排序数组元素到一个新的数组
int i = A.length-1;
for(;i >= 0; i --) {
B[C[A[i]]-1] = A[i];
C[A[i]] = C[A[i]] - 1;
}
return B;
}

public int findMax(int[] A) {
int temp = 0;
for(int i:A) {
if(i > temp) {
temp = i;
}
}
return temp;
}
}
/**
*实现的最大堆的插入和删除操作
*
*/
public class HeapSort {
/*
* 删除堆中位置是index处的值
* 操作原理是:当删除节点的数值时,原来的位置就会出现一个孔
* 填充这个孔的方法就是,把最后的叶子的值赋给该孔,最后把该叶子删除
* @param heap 一个最大堆
*/
public static void delete(List<Integer> heap, int index) {
//把最后的一个叶子的数值赋值给index位置
heap.set(index, heap.get(heap.size() - 1));
//下沉操作
//heapDown2(heap, index);
heapDown(heap, index); //节点下沉
//把最后一个位置的数字删除
heap.remove(heap.size() - 1);
}


/**
* 节点下沉递归实现
* 删除一个堆中一个数据的时候,根据堆的性质,应该把相应的位置下移,才能保持住堆性质不变
* @param heap 保持最大堆元素的数组
* @param index 被删除的那个节点的位置
*/
public static void heapDown(List<Integer> heap, int index) {
//因为第一个位置存储的是空值,不在考虑之内
int n = heap.size() - 2;

//记录最大的那个儿子节点的位置
int child = -1;

//2*index>n说明该节点没有左右儿子节点了,那么就返回
if (2 * index > n) {
return;
} //如果左右儿子都存在
else if (2 * index < n) {

//定义左儿子节点
child = 2 * index;
//如果左儿子小于右儿子的数值,取右儿子的下标
if ((Integer) heap.get(child) < (Integer) heap.get(child + 1)) {
child++;
}

}//如果只有一个儿子(左儿子节点)
else if (2 * index == n) {
child = 2 * index;
}

if ((Integer) heap.get(child) > (Integer) heap.get(index)) {
//交换堆中的child,和index位置的值
swap(heap, child, index);

//完成交换后递归调用,继续下降
heapDown(heap, child);
}
}

//非递归实现
public static void heapDown2(List<Integer> heap, int index) {
int child = 0;//存储左儿子的位置

int temp = (Integer) heap.get(index);
int n = heap.size() - 2;
//如果有儿子的话
for (; 2 * index <= n; index = child) {
//获取左儿子的位置
child = 2 * index;
//如果只有左儿子
if (child == n) {
child = 2 * index;
} //如果右儿子比左儿子的数值大
else if ((Integer) heap.get(child) < (Integer) heap.get(child + 1)) {
child++;
}

//如果数值最大的儿子比temp的值大
if ((Integer) heap.get(child) >temp) {
//交换堆中的child,和index位置的值
swap(heap, child, index);
} else {
break;
}
}
}


//打印链表
public static void print(List<Integer> list) {
for (int i = 1; i < list.size(); i++) {
System.out.print(list.get(i) + " ");
}
System.out.println();
}

//把堆中的a,b位置的值互换
public static void swap(List<Integer> heap, int a, int b) {
//临时存储child位置的值
int temp = (Integer) heap.get(a);

//把index的值赋给child的位置
heap.set(a, heap.get(b));

//把原来的child位置的数值赋值给index位置
heap.set(b, temp);
}

//向最大堆中插入元素
public static void insert(List<Integer> heap, int value) {
//在数组的尾部添加要插入的元素
if(heap.size()==0)
heap.add(0);//数组下标为0的位置不放元素
heap.add(value);
//开始上升操作
// heapUp2(heap, heap.size() - 1);
heapUp(heap, heap.size() - 1);

}

//节点上浮,让插入的数和父节点的数值比较,当大于父节点的时候就和节点的值相交换
public static void heapUp(List<Integer> heap, int index) {

//注意由于数值是从小标为一开始,当index = 1的时候,已经是根节点了
if (index > 1) {
//保存父亲的节点
int parent = index / 2;

//获取相应位置的数值
int parentValue = (Integer) heap.get(parent);
int indexValue = (Integer) heap.get(index);
//如果父亲节点比index的数值小,就交换二者的数值
if (parentValue < indexValue) {
//交换数值
swap(heap, parent, index);
//递归调用
heapUp(heap, parent);
}

}
}

//非递归实现
public static void heapUp2(List<Integer> heap, int index) {
int parent = 0;
for (; index > 1; index /= 2) {
//获取index的父节点的下标
parent = index / 2;

//获得父节点的值
int parentValue = (Integer) heap.get(parent);
//获得index位置的值
int indexValue = (Integer) heap.get(index);

//如果小于就交换
if (parentValue < indexValue) {
swap(heap, parent, index);
}
}
}
/*根据树的性质建堆,树节点前一半一定是分支节点,即有孩子的,所以我们从这里开始调整出初始堆*/
public static void adjust(List<Integer> heap){
for (int i = heap.size() / 2; i > 0; i--)
adjust(heap,i, heap.size()-1);//heap[heap.size()/2,...n]之后都为树的叶子节点, 每一叶子节点本身就是包含一个元素的最大堆, 故只需要构建heap.size()/2之前元素的最大堆

System.out.println("=================================================");
System.out.println("调整后的初始堆:");
print(heap);
}
/**
* 调整堆,使其满足堆得定义
* @param i
* @param n
*/
public static void adjust(List<Integer> heap,int i, int n) {

int child;
for (; i <= n / 2; ) {
child = i * 2;
if(child+1 <= n && heap.get(child) < heap.get(child+1))
child+=1;/*使child指向值较大的孩子*/
if(heap.get(i)< heap.get(child)){
swap(heap,i, child);
/*交换后,以child为根的子树不一定满足堆定义,所以从child处开始调整*/
i = child;

} else break;
}
}

//对一个最大堆heap排序
public static void heapSort(List<Integer> heap) {

for (int i = heap.size()-1; i > 0; i--) {
/*把根节点跟最后一个元素交换位置,调整剩下的n-1个节点,即可排好序*/
swap(heap,1, i);
adjust(heap,1, i - 1);
}
}
public static void main(String args[]) {
List<Integer> array = new ArrayList<Integer>(Arrays.asList(null,
1, 2, 5, 10, 3, 7, 11, 15, 17, 20, 9, 15, 8, 16));
adjust(array);//调整使array成为最大堆

//delete(array,8);//堆中删除下标是8的元素
//System.out.println("删除后");
// print(array);
//insert(array, 99);//堆中插入
// print(array);



heapSort(array);//排序
System.out.println("将堆排序后:");
print(array);
System.out.println("-------------------------");





// List<Integer> array1=new ArrayList<Integer>();
// insert(array1,0);
// insert(array1, 1);insert(array1, 2);insert(array1, 5);
// insert(array1, 10);insert(array1, 3);insert(array1, 7);
// insert(array1, 11);insert(array1, 15); insert(array1, 17);
// insert(array1, 20);insert(array1, 9);
// insert(array1, 15);insert(array1, 8);insert(array1, 16);
// print(array1);
//
// System.out.println("==============================");
// array=new ArrayList<Integer>(Arrays.asList(null,45,36,18,53,72,30,48,93,15,35));
// adjust(array);
// insert(array, 80);//堆中插入
// print(array);
// delete(array,2);//堆中删除80的元素
// print(array);
// delete(array,2);//堆中删除72的元素
// print(array);

}
}
public class InsertSort {
public static void main(String[] args) {
int num[] = { 3, 1, 5, 4, 123, 55, 33, 123 };
// new InsertSort().sort(num);
// for (int n : num) {
// System.out.print(n + " ");
// }
insertSort(num);
for (int n : num) {
System.out.print(n + " ");
}

}


public static void insertSort(int[] arr){
int i, j;
int n = arr.length;
int target;

//假定第一个元素被放到了正确的位置上
//这样,仅需遍历1 - n-1
for (i = 1; i < n; i++)
{
j = i;
target = arr[i];

while (j > 0 && target < arr[j - 1])
{
arr[j] = arr[j - 1];
j--;
}

arr[j] = target;
}
}


void sort(int num[]){
for(int i=1;i<num.length;i++){
for(int j=i;j>0 && Utils.less(num[j],num[j-1]);j--){
Utils.exec(num, j, j-1);
}
}
}

}
public class MergeSort {
public static void main(String[] args) {
int num[] = {5,2,4,7,1,3,2,6,9};
sort(num, 0, num.length-1);
for (int n : num) {
System.out.print(n + " ");
}
}

//初始low=0; high=num.length-1
public static void sort(int num[],int low,int high){
if(low<high){
int mid = low+(high-low)/2;
//System.out.println("左边:" + low);
//1:low =0,mid=4,high=8;
//2:low=0,mid=2,high=4;
//3:low=0,mid=1,high=2;
//4:low=0,mid=0,high=1;
//5:low=3,mid=3,high=4;
//6:low=5,mid=6,high=8;
//7:low=5,mid=5,high=6;
//8:low=7,mid=7,high=8
sort(num,low,mid); //每一次结果会入栈(栈桢:保存函数的信息),low=0,mid=0,high=1时不满足(0=0), 会弹栈,回到上次执行的下一条语句出
//System.out.println("右边:" + low);
//1:low=0,mid=0,high=1;
//2:low=0,mid=1,high=2;
//3:low=0,mid=2,high=4;
//4:low=3,mid=3,high=4;
//5:low=0,mid=4,high=8;
//6:low=5,mid=5,high=6;
//7:low=5,mid=6,high=8;
//8:low=7,mid=7,high=8
sort(num,mid+1,high);//上一条弹栈的值为low=0,mid=0,high=1(mid+1=1=high(1)),不满足,弹栈,进入下一条语句;// 下一条返回后继续执行low=0,mid=1,high=2,此时不满足,执行下一条; 再次返回后low=0,mid=2,high=4,此时满足if条件,因此构建此语句的调用栈
//1:low=0,mid=0,high=1;
//2:low=0,mid=1,high=2;
//3:low=3,mid=3,high=4;
//4:low=0,mid=2,high=4;
//5:low=5,mid=5,high=6;
//6:low=7,mid=7,high=8;
//7:low=5,mid=6,high=8;
//8:low=0,mid=4,high=8
merge(num,low,mid,high);//上一条的弹栈的值,low=0,mid=0,high=1,执行结束后num={2,5,4,7,1,3,2,6,9},回来继续执行,上一条语句继续执行弹栈
}

}



public static void merge(int[] num, int low, int mid, int high) {
int copyNum[]=new int[num.length];
for(int i=0;i<=high;i++){
copyNum[i] = num[i];
}
int left = low;
int right = mid+1;
int current = low;
while(left<=mid && right<=high){
if(copyNum[left]<copyNum[right]){
num[current++]=copyNum[left];
left++;
}else{
num[current++]=copyNum[right];
right++;
}
}

int remaining = mid-left;
for(int i=0;i<=remaining;i++){
num[current+i]=copyNum[left+i];
}
}

}
public class QuickSort {
public static void main(String[] args) {
int num[] = {7,6,5,10,4,4,3,2,1 };
System.out.println("初始数组:==============================");
for (int n : num) {
System.out.print(n + " ");
}
new QuickSort().sort(num, 0, num.length-1);//
System.out.println("快速排序的结果:=========================");
for (int n : num) {
System.out.print(n + " ");
}

// int num1[] = {7,8,5,9,4,12,2,6 }; //System.out.println("length: " + num1.length);
// //for Ken quick sort
// new QuickSort().sortKen(num1, 0, num1.length-1);
// System.out.println("ken quick sort 的结果为: ================");
// for (int n : num1) {
// System.out.print(n + " ");
// }
}

public static void sort(int num[], int left, int right) {
if (left < right) {
int index = partition(num, left, right);//基准元素的下标, 数组的划分调用
sort(num, left, index-1);
sort(num, index, right);
}

}

public static int partition(int[] num, int left, int right) {
if(num==null || num.length<=0 || left<0 || right>=num.length){
return 0;
}
int prio = num[left + (right - left) / 2]; //基准元素, 中间位置, 可以是第一个或者最后一个
while(left<=right){
while (num[left] > prio)
left++; //如果比基准元素小的位置不动
while (num[right] < prio)
right--; //如果比基准元素大的位置不动
if (left<=right) { //如果有左边的元素大于右边的元素, 则进行交换
swap(num, left, right);
left++;
right--;
}
}
return left;
}

public static void swap(int[] num, int left, int right) {
int temp = num[left];
num[left] = num[right];
num[right] = temp;
}





//for Ken quick sort
void sortKen(int[] num, int left, int right) { //num, 0, 7
if (left <right) {
int index = partitionKen(num, left, right);//基准元素的下标, 数组的划分调用
sortKen(num, left, index-1);
sortKen(num, index, right);
}

}

public int partitionKen(int[] num, int p, int r){
int temp = num[r];
int i = 0;
for(int j = p; j <= r-1; j ++){
if (num[j] <= temp){
i = i + 1;
//System.out.println(i + " " + j);
try {
swap(num, num[i], num[j]);
}catch (ArrayIndexOutOfBoundsException e){
System.out.println("i:" + i + "j: " + j);
e.printStackTrace();
}


}
}
swap(num, num[i+1], num[r]);
return i + 1;
}
}
public class RadixSort {
public static void main(String[] args) {
int array[]={1,99,1,3,5,6,7,9,12,89,13123,10};
new RadixSort().sort(array);
for(int a:array)
System.out.print(a+" ");

//System.out.println(Math.pow(10, 3)%10);
}
void sort(int []array){
//1.找出数组array中最大值
int max = findMax(array);
int time = 0; //time记录最大数的位数
while(max>0){
max/=10;
time++;
}
//System.out.println("time " + time);
//2.每位数都是从0到9
LinkedList<Integer> queue[]=new LinkedList[10];
//LinkedList<Integer>[] test = new LinkedList[20];
for(int i=0;i<10;i++){
queue[i]=new LinkedList<>(); //为每位数申请一个list空间
}
//3.对每位数对应的数组排序
for(int i=0;i<time;i++){ //0代表个位,1代表十位,...
//3.1
for(int j=0;j<array.length;j++){
//queue[array[j]%(int)Math.pow(10, i+1)/(int)Math.pow(10, i)].add(array[j]);
//(int)Math.pow(10, i): 10的i次方除以10取余数
//array[j]/(int)Math.pow(10, i)%10: array[j]除以10的i次方然后除以10取余数, 得到每个数的个位, 十位,..对应的数字
queue[array[j]/(int)Math.pow(10, i)%10].add(array[j]);
//queue[0]存储个位为0的所有数, queue[1]存储个位为1的所有数
}
//System.out.println("***********");
// for (int ii = 0; ii < 10; ii ++){
// for (Integer jj:queue[ii]){
// System.out.println(jj);
// }
// System.out.println("========*****");
// }
//3.2 按照位数重新组织数列(先按个位, 然后十位,...)
int count = 0;
for(int k=0;k<10;k++){
while(!queue[k].isEmpty()){
array[count++]=queue[k].remove(); //返回queue[k]的第一个元素给array[0]
}
}

System.out.println("***********");
for (int j = 0; j < array.length; j ++){
System.out.println(array[j]);
}


}


}

public int findMax(int[] array) {
int max = 0;
for(int j=0;j<array.length;j++){
if(array[j]>array[max]){
max = j;
}
}
return array[max];
}

}
public class SelectSort {
public static void main(String[] args) {
int num[] = { 3, 1, 5, 4, 123, 55, 33, 123 };
new SelectSort().sort(num);
for (int n : num) {
System.out.print(n + " ");
}
}
void sort(int num[]){
for(int i=0;i<num.length-1;i++){
int min = i;
for(int j=i+1;j<num.length;j++){
if(num[min]>num[j]){
min = j;
}
}
if(min!=i)
Utils.exec(num,i,min);
}
}
}
public class Utils {

public static void exec(int[] num, int i, int min) {
int temp = num[i];
num[i] = num[min];
num[min]= temp;
}

public static boolean less(int i, int j) {
return i < j ? true : false;
}


}
//希尔排序
public class ShellSort {
public static void main(String[] args) {
int num[] = { 3, 1, 5, 4, 123, 55, 33, 123 };
new ShellSort().sort(num);
for (int n : num) {
System.out.print(n + " ");
}
}
void sort(int num[]){
int N = num.length;
int gap = 1;
while(gap<N/2) gap = 2*gap+1;
while(gap>=1){
////从第gap个元素,逐个对其所在组进行直接插入排序操作
for(int i=gap;i<N;i++){
////插入排序采用交换法
for(int j=i; j >= gap && Utils.less(num[j], num[j-gap]);j-=gap){
Utils.exec(num, j, j-gap);
}
}
gap = gap/2;
}
}


/**
* 希尔排序 针对有序序列在插入时采用移动法。
* @param arr
*/
public static void sort1(int []arr){
//增量gap,并逐步缩小增量
for(int gap=arr.length/2;gap>0;gap/=2){
//从第gap个元素,逐个对其所在组进行直接插入排序操作
for(int i=gap;i<arr.length;i++){
int j = i;
int temp = arr[j];
if(arr[j]<arr[j-gap]){
while(j-gap>=0 && temp<arr[j-gap]){
//移动法
arr[j] = arr[j-gap];
j-=gap;
}
arr[j] = temp;
}
}
}
}
}
posted @ 2018-03-21 18:20  ken007  阅读(199)  评论(0编辑  收藏  举报