此篇为main方法中调用的方式展示各排序方法的使用
package cn.first.start;
public class VarietySort {
//拓扑排序,用来确认事物发生的顺序
//选择排序、快速排序、希尔排序、堆排序不是稳定的排序算法
//冒泡排序、插入排序、归并排序、基数排序是稳定的排序算法
public static void main(String[] arg){
int i;
int[] a = {10,40,30,60,80,30,20};
//冒泡排序
//sort(a,a.length);
//快速排序
sort2(a,0,a.length-1);
//选择排序
//sort3(a,a.length);
//插入排序
//sort4(a,a.length);
//堆排序
//sort5(a);
//System.out.println(Arrays.toString(a));
for(i=0;i<a.length;i++){
System.out.println(a[i]+"\n");
}
//希尔排序
//VarietySort shell = new VarietySort();
/*System.out.print("排序前:\t\t");
shell.printAll(a);
shell.sort6(a);
System.out.print("排序后:\t\t");
shell.printAll(a);*/
//基数排序
/*System.out.print("排序前:\t\t");
shell.printAll(a);
shell.sort7(a);
//shell.sort(a);
System.out.print("排序后:\t\t");
shell.printAll(a);*/
}
/**
* 冒泡排序
* @param a
* @param n
*/
public static void sort(int a[],int n){
int i,j,num;
int flag;
for(i=n-1;i>0;i--){
flag = 0;
for(j=0;j<i;j++){
if(a[j]>a[j+1]){
num = a[j+1];
a[j+1] = a[j];
a[j] = num;
flag=1;
}
}
if(flag==0)
break;
}
}
/**
* 快速排序,取起始位置的元素,从左往右找比起小的元素,替换。从右往左找比起大的元素,替换。循环调用
* @param a
* @param l
* @param r
*/
public static void sort2(int a[],int l,int r){
if(l<r){
int i,j,x;
i=l;//左第一个数
j=r;//右第一个数
x=a[i];
while(i<j){
while(i<j && a[j]>x)
j--;//从右向左找第一个小于x的数
if(i<j)
a[i++]=a[j];
while(i<j && a[i]<x)
i++;//从左向有找第一个大于x的数
if(i<j)
a[j--]=a[i];
}
a[i]=x;
sort2(a,l,i-1);
sort2(a,i+1,r);
}
}
/**
* 选择排序,选择数组中最小的元素放在首位
* @param a
* @param n
*/
public static void sort3(int a[],int n){
int i, //无序区中末尾位置
j, //有序区中开始位置
min, //无序区中最小的元素位置
num;
for(i=0;i<n;i++){
min = i;
for(j=i+1;j<n;j++){
if(a[j]<a[min])
min = j;
}
//若min!=i,则替换a[i] 和 a[min]的位置,是a[]中的元素是有序的
if(min!=i){
num = a[i];
a[i] = a[min];
a[min] = num;
}
}
}
/**
* 直接插入排序,分为有序区和无序区,从无序区中找第一个元素,放在有序区的合适的位置
* @param a
* @param n
*/
public static void sort4(int a[],int n){
int i,j,k;
for(i=1;i<n;i++){
//为a[i]在前面的有序区内找一个合适的位置
for(j=i-1;j>=0;j--){
if(a[j]<=a[i])
break;
}
//如找到了一个合适的位置
if(j!=i-1){
//将比a[i]大的数据向后移
int temp = a[i];
for(k=i-1;k>j;k--)
a[k+1] =a[k];
//将a[i]放在正确的位置上
a[k+1] = temp;
}
}
}
public static int[] sort4(int[] array){
int j;
//从下标为1的元素开始选择合适的位置插入,因为下标为0的只有一个元素,默认是有序的
for(int i = 1 ; i < array.length ; i++){
int tmp = array[i];//记录要插入的数据
j = i;
while(j > 0 && tmp < array[j-1]){//从已经排序的序列最右边的开始比较,找到比其小的数
array[j] = array[j-1];//向后挪动
j--;
}
array[j] = tmp;//存在比其小的数,插入
}
return array;
}
/**
* 堆排序,分为大顶堆与小顶堆,升序用大顶堆,降序用小顶堆
* @param arr
*/
public static void sort5(int arr[]){
//1.构建大顶堆
for(int i=arr.length/2-1;i>=0;i--){
//从第一个非叶子节点从下到上,从右至左调整结构
adjustHeap(arr,i,arr.length);
}
//2.调整堆结构,交换堆顶结构与末尾元素
for(int j=arr.length-1;j>0;j--){
swap(arr,0,j);//将堆顶元素和末尾元素进行交换
adjustHeap(arr,0,j);//重新对堆进行调整
}
}
/**
* 调整大顶堆,只是调整过程,建立在大顶堆已构建的基础上
* @param arr
* @param i
* @param length
*/
public static void adjustHeap(int []arr,int i,int length){
int temp = arr[i];//先取出当前元素
for(int k=2*i+1;k<length;k=k*2+1){
//从i节点的左子节点开始,也就是2i+1处开始
if(k+1<length && arr[k]<arr[k+1]){
//如果左子节点小于右子节点,取右子节点
k++;
}
//如果子节点大于父节点,将子节点的值赋值给父节点(不用做交换)
if(arr[k]>temp){
arr[i]=arr[k];
i=k;
}else{
break;
}
}
arr[i]=temp;//将temp的值放到最终位置
}
public static void swap(int arr[],int a,int b){
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
/**
* 希尔排序,以数组长度的一半为一组的长度进行划分,以直接插入排序进行,再以一半的一半进行分组,循环。
* @param list
*/
public void sort6(int[] list){
int gap = list.length/2;
while(1<=gap){
//把距离为gap的元素编为一个组,扫描所有组
for(int i=gap;i<list.length;i++){
int j=0;
int temp = list[i];
//对距离为gap的元素进行排序
for(j=i-gap;j>=0 && temp<list[j];j=j-gap){
list[j+gap] = list[j];
}
list[j+gap] = temp;
}
System.out.format("gap = %d:\t",gap);
printAll(list);
gap = gap/2;//减少增量
}
}
//打印完整序列
public static void printAll(int[] list){
for(int value : list){
System.out.print(value + "\\t");
}
System.out.println();
}
/**
* 合并排序,分而治之,将整个数组等分为若干的数组,比较排序。左边取值按顺序放到右边,复制排序好的数组到之前的数组
* @param arr
*/
public static void sort7(int []arr){
int []temp = new int[arr.length];
//在排序前,先建好一个长度等于原数组长度的临时数组,
//避免递归中频繁开辟空间
sort(arr,0,arr.length-1,temp);
}
private static void sort(int[] arr,int left,int right,int []temp){
if(left<right){
int mid = (left+right)/2;
sort(arr,left,mid,temp);
//左边归并排序,使得左子序列有序
sort(arr,mid+1,right,temp);
//右边归并排序,使得右子序列有序
merge(arr,left,mid,right,temp);
//将两个有序子数组合并操作
}
}
private static void merge(int[] arr,int left,int mid,int right,int[] temp){
int i = left;//左序列指针
int j = mid+1;//右序列指针
int t = 0;//临时数组指针
while (i<=mid && j<=right){
if(arr[i]<=arr[j]){
temp[t++] = arr[i++];
}else {
temp[t++] = arr[j++];
}
}
while(i<=mid){//将左边剩余元素填充进temp中
temp[t++] = arr[i++];
}
while(j<=right){//将右序列剩余元素填充进temp中
temp[t++] = arr[j++];
}
t = 0;
//将temp中的元素全部拷贝到原数组中
while(left <= right){
arr[left++] = temp[t++];
}
}
/**
* 基数排序,按个十百千万的位数在0-9的桶中进行排序,知道最大位数排完便完成
* @param list
* @param begin
* @param end
* @param digit
*/
public void Sort8(int[] list, int begin, int end, int digit) {
final int radix = 10; // 基数
int i = 0, j = 0;
int[] count = new int[radix]; // 存放各个桶的数据统计个数
int[] bucket = new int[end - begin + 1];
// 按照从低位到高位的顺序执行排序过程
for (int d = 1; d <= digit; d++) {
// 置空各个桶的数据统计
for (i = 0; i < radix; i++) {
count[i] = 0;
}
// 统计各个桶将要装入的数据个数
for (i = begin; i <= end; i++) {
j = getDigit(list[i], d);
count[j]++;
}
// count[i]表示第i个桶的右边界索引
for (i = 1; i < radix; i++) {
count[i] = count[i] + count[i - 1];
}
// 将数据依次装入桶中
// 这里要从右向左扫描,保证排序稳定性
for (i = end; i >= begin; i--) {
j = getDigit(list[i], d);
// 求出关键码的第k位的数字, 例如:576的第3位是5
bucket[count[j] - 1] = list[i];
// 放入对应的桶中,count[j]-1是第j个桶的右边界索引
count[j]--; // 对应桶的装入数据索引减一
}
// 将已分配好的桶中数据再倒出来,此时已是对应当前位数有序的表
for (i = begin, j = 0; i <= end; i++, j++) {
list[i] = bucket[j];
}
}
}
// 获取x这个数的d位数上的数字
// 比如获取123的1位数,结果返回3
public int getDigit(int x, int d) {
int a[] = {
1, 1, 10, 100
}; // 本实例中的最大数是百位数,所以只要到100就可以了
return ((x / a[d]) % 10);
}
public int[] sort(int[] list) {
Sort8(list, 0, list.length - 1, 3);
return list;
}
}