- 直接插入排序
- 希尔排序(二分插入)
- 简单选择排序
- 堆排序
- 归并排序
- 快速排序
- 冒泡排序
- 桶式排序(基数排序)
1、直接插入排序
插入排序由N-1趟排序组成,对于p=1到p=N-1趟,保证位置0到p上的元素为已排序状态。在第p趟,将位置p上的元素向左移动到正确位置。
S(N)=O(N^2)
public static <AnyType extends Comparable<? super AnyType>>
void insertionSort(AnyType[] a)
{
int j;
for(int p=1; p<a.length; p++)
{
AnyType tmp = a[p]; //tmp用来存储位置p上的元素
for(j=p;j>0&&tmp.compareTo(a[j-1])<0;j--) //j指针指向p,然后左移直至右边的元素>=a[p]
a[j] = a[j-1]; //关键步骤就是边移动指针边交换元素,类似排队时向前一个一个插队
a[j] =tmp; //找到正确位置以后a[j]就不能为a[j-1]咯
}
}
2、希尔排序 (二分插入)
希尔排序通过比较相距一定间隔的元素来工作,各趟比较所用的距离随着算法的进行而减小,直到比较相邻元素的最后一趟排序为止。设增量序列为h[n], h[t]=N/2, h[k]=h[k+1]/2。即从数组长度的一半开始为原始增量,不断二分直至为1.
public static <AnyType extends Comparable<? super AnyType>>
void shellSort(AnyType[] a)
{
int j;
for(int gap=a.length/2; gap>0; gap/=2) //不断二分直至为1
for(int i=gap; i<a.length; i++) //i指针指向gap并后移
{
AnyType tmp = a[i];
for(j=i; j>=gap && tmp.compareTo(a[j-gap])<0; j-=gap) //j指针执行向前比较,交换相距gap的元素的值
a[j]=a[j-gap]; //同插入排序的非显示交换
a[j]=tmp;
}
}
3、简单选择排序
简单选择排序类似冒泡排序,但是不需要依次相邻交换,而是新建一个临时变量存储最小值下标,不断缩小范围寻找最小值,然后依次排列。
private static<AnyType extends Comparable<? super AnyType>>
void choiceSort(AnyType[] a)
{
for int(i=0; i<a.length; i++) //排序的趟数
{
int min=i; //当前下标初始化为最小值下表
for(int j=i+1;j<a.length;j++) //寻找最小值,重置min
{
if( (a[min]).compareTo(a[j])>0 ){
min=j;
}
}
if(i!=min){ //找到不同的最小值,a[min]和a[i]互换
AnyType[] tmp=a[min];
a[min]=a[i];
a[i]=tmp;
}
}
}
4、堆排序
堆排序就是利用了二叉堆这个特殊数据结构的特性–排列规律,每次能够删除根节点(最大或最小值)。每次删除根节点后,再将根节点放在尾部以实现排序。简而言之就是对未排序部分做下滤操作后将根节点放于尾部。
/**这里要利用到堆结构排列在数组中后的特殊特性。不理解可以先画个堆自己插入、删除走一遍,观察在数组中的访问步骤。
*对于数组中任一位置i上的元素,其左儿子在位置2i上,它的父亲在位置[i/2]上。(0位置为空的情况下)
*/
//堆排序
private static int leftChild(int i)
{
return 2*i+1;
}
private static <AnyTYpe extends Comparable<? super AnyType>>
void percDown(AnyType[] a, int i, int n) //三个参数,数组对象,节点,数组长度范围
{
int child;
AnyType tmp;
for(tmp=a[i]; leftChild(i)<n;i=child;)
{
child=leftChild(i); //child类似指针指向左子节点,开始遍历
if(child!=n-1&&a[child].compareTo(A[child+1]<0) //只要小于右边就一直右移,找到最大的字节点
child++;
if(tmp.compareTo(a[child]<0) //如果i小于它的字节点
a[i]=a[child]; //自节点上滤
else
break;
}
a[i]=tmp; //相当于a[child]=tmp;就是将a[i]值跟它的字节点互换
}
public static<AnyType extends Comparable<? super AnyType>>
void heapSort(AnyType[] a)
{
for(int i=a.lenght/2;i>=0;i--) //根据二叉堆性质--任一位置i上的元素的父亲在[i/2]上,即从堆结构的尾部依次遍历非叶子节点,直到根节点
percDown(a,i,a.length); //依次对非叶子节点进行上滤,以此来构建堆
for(int i=a.length-1;i>0;i--) //这里的i--作用是取出最大值后范围就缩小了
{
swapReferences(a,0,i); //存放在0位置的根节点,把根节点的值跟末尾i位置的值互换,这一步算作删除最大值操作,或者叫取出最大值
percDown(a,0,i); //取出后根节点不满足二叉堆性质了,所以前面i个值需要重新构建二叉堆,也就是重新上滤
}
}
5、归并排序
归并排序就是将两个有序数组合并,双指针同时遍历两个数组,比较大小并依次排放在第三个新建的数组中。通过递归地将数组不断二分再分别合并,最终会二分至只有1个元素的数组从而完成排序。
//将两个有序数组进行组合的merge方法
public static<AnyType extends Comparable<? super AnyTYpe>>
void merge(AnyType[] a,AnyType[] tmpArray,int leftPos,int rightPos, int rightEnd)
{
int leftEnd = rightPos - 1;
int tmpPos = leftPos;
int numElements = rightEnd - leftPos + 1;
while(leftPos<=leftEnd&&rightPos<=rightEnd) //leftPos和rightPos双指针在范围内同时右移进行比较,将小的数存入tmpArray
if(a[leftPos].compareTo(a[rightPos])<=0)
tmpArray[tmpPos++] = a[leftPos++];
else
tmpArray[tmpPos++] = a[rightPos++];
//当上述while循环结束,以下两个while循环检查还未用完的数组,将余下部分拷贝到tmpArray中
while(leftPos <= leftEnd)
tmpArray[tmpPos++] = a[leftPos++];
while(rightPos <= rightEnd)
tmpArray[tmpPos++] = a[rightPos++];
//将tmpArray元素拷回
for(int i=0;i<numElements;i++,rightEnd--)
a[rightEnd]=tmpArray[rightEnd];
}
//归并操作的四参数重载方法
private static<AnyType extends Comparable<? super AnyType>>
void mergeSort(AnyType[] a, AnyTYpe[] tmpArray, int left, int right)
{
if(left<right)
{
int center = (left+right)/2;
//递归调用执行合并排序操作,不断划分为更小的有序数组(2个数)
mergeSort(a,tmpArray,left,center);
mergeSort(a,tmpArray,center+1,right);
//合并初始的两个最大有序数组
merge(a,tmpArray,left,center+1,right);
}
}
//归并操作的单参数重载方法
public static<AnyType extends Comparable<? super AnyType>>
void mergeSort(AnyType[] a)
{
AnyType[] tmpArray = (AnyType[]) new Comparable[a.length]; //根据待排序数组长度新建临时数组
mergeSort(a,tmpArray,0,a.length-1); //根据待排序数组提取四参数传入
}
6、快速排序
快速排序即选取枢纽元,将比它小的放在左边,大的放在右边,然后递归地对左右两边进行快排。关键点在于选取枢纽元的方法,这里采用三数分割法,选取的同时将三个数排序,将枢纽元放在n-1处,可以缩小排序范围。
//快速排序
public stativ<AnyType extends Comparable<? super AnyType>>
void quickSort(AnyType[] a)
{
quickSort(a,0,a.length-1);
}
//三数分割法
private static<AnyType extends Comparable<? super AnyType>>
void median3(AnyType[] a,int left, int right)
{
int center=(left+right)/2; //确定center值
if(a[center].compareTo(a[left]<0) //如果center<left
swapReferences(a, left, center); //调换center、left位置
if(a[right].compareTo(a[left])<0) //如果right<left
swapReferences(a,left,right); //调换right、left位置 , 这样能够确保最小的放在left处
if(a[right].compareTo(a[center]<0) //如果right<center
swapReferences(a,center,right); //调换right、center位置 ,这样就能保证最大的放在right处,即left<center<right排列
swapReferences(a,center,right-1); //将center放在right-1的位置
return a[right-1]; //返回三数中值
}
//快排主函数
private static<AnyType extends Comparable<? super AnyType>>
void quickSort(AnyType[] a,int left, int right)
{
//定义CUTOFF为10,相差10以内直接插入排序吧。。
final CUTOFF = 10;
if(left+CUTOFF<=right)
{
//取中值pivot
AnyType pivot = median3(a,left,right);
//i指针从left开始,j指针从right-1开始
int i=left, j=right-1;
for( ; ; )
{
while(a[++i].compareTo(pivolt)<0){} //i指针右移寻找较大的数(>=)
while(a[--j].compareTo(pivolt)>0){} //j指针左移寻找较小的数(<=)
if(i<j) //i、j指针没有相遇则交换i、j指向的值,即大的放右边小的放左边
swapReferences(a,i,j);
else //相遇则跳出
break;
}
//最后一步,将i指向的数与放在尾部的中值互换,完成小的在中值左边,大的在中值右边
swapReferences(a,i,right-1);
//递归地分别对左右两边快排
quickSort(a,left,i-1);
quickSort(a,i+1,right);
}
else
insertionSort(a,left,right);
}
7、 冒泡排序
冒泡排序和选择排序类似,但是没有建立临时变量,而是通过相邻交换将最大或最小值不断后移达到依次排序的效果。
private static<AnyType extends Comparable<? super AnyType>>
void bubbleSort(AnyType[] a)
{
int len=a.length-1;
for(i=0;i<len;i++) //排序的趟数
for(j=0;j<len-i-1;j++) //j的范围不断缩小,第i趟排列0到len-i-1个数
{
//将最大的数依次后移放到最后,可以理解为每次最大的泡向上冒
if( (a[j]).compareTo(a[j+1])>0 )
{
AnyType[] temp=a[j];
a[j]=a[j+1];
a[j+1]=temp;
}
}
}
桶式排序(基数排序)
占坑