您的位置:首页 > 编程语言 > Java开发

Java排序算法以及算法改进总结(计数排序、基数排序、桶排序)

2017-10-16 20:17 836 查看
算法复习,代码是最好的说明!

一、计数排序:

算法:

统计数组A中每个值A[i]出现的次数,存入C[A[i]]

从前向后,使数组C中的每个值等于其与前一项相加,这样数组C[A[i]]就变成了代表数组A中小于等于A[i]的元素个数

从后向前,填充目标数组B:将数组元素A[i]放在数组B的第C[A[i]]个位置(下标为C[A[i]] - 1),每放一个元素就将C[A[i]]递减

分析:

平均最好最坏辅助存储稳定性
O(n+k)O(n+k)O(n+k)O(n+k)稳定

代码:

/**
* 计数排序
* @param array
* @param
*/
void countingSort_1(int[] array){

int max = array[array.length-1];

for (int i = 0; i < array.length-1; i++) {
if (array[i]>max) max = array[i];
}

int[] B = new int[array.length];
int[] C = new int[max+1];

for (int i = 0; i < array.length; i++) {
C[array[i]]++;
}

for (int i = 1; i < C.length; i++) {
C[i] += C[i-1];
}

for (int i = array.length-1; i >=0; i--) {

B[--C[array[i]]] = array[i];

}

System.arraycopy(B,0,array,0,array.length);
}

/**
* 计数排序改进,缩小C,归并法处理前后项相加
* @param array
*/
void countingSort_2(int[] array){

int[] B = new int[array.length];
int max = 0;
int min = 0 ;

for (int i : array) {
if (i>max) max = i;
if (i<min) min = i;

}

int[] C = new int[max - min + 1];

for (int i = 0; i < array.length; i++) {
C[array[i]-min]++;
}

//        for (int i = 1; i < C.length; i++) {
//            C[i] += C[i-1];
//        }
mergeAdd(C);

for (int i = array.length-1; i >=0; i--) {
B[--C[array[i]]] =array[i];
}

System.arraycopy(B,0,array,0,array.length);

}

/**
* logn比n
* @param array
*/
void mergeAdd(int[] array){
for (int i = 1; i < array.length; i*=2) {
for (int j = 0; j < array.length; j+=2*i) {
for (int k = j+i; k <j+2*i; k++) {
if (k >= array.length) break;
array[k] += array[j+i-1];
}
}
}
}


二、基数排序:

LSD(Least significant digital):

算法:

先从kd 开始排序,再对kd-1进行排序,依次重复,直到按k1排序分组分成最小的子序列后。

最后将各个子序列连接起来,便可得到一个有序的序列

分析:

平均最好最坏辅助存储稳定性
O(d*(n+r))O(d*(n+r))O(d*(n+r))O(n+r)稳定
d为关键字个数,n为待排序元素个数,r为关键字取值基数

代码:

/**
* lsd
* @param array
* @param d
*/
void radixSort_LSD(int[] array,int d){
int k = 0,m = 1,n = 1;
int[][] temp = new int[10][array.length];
int[] order = new int[10];

while (m<=d){

for (int i = 0; i < array.length; i++) {
int lsd = (array[i]/n)%10;
temp[lsd][order[lsd]++] = array[i];
}

for (int i = 0; i < 10; i++) {
if (order[i] == 0) continue;
for (int j = 0; j < order[i]; j++) {
array[k++] = temp[i][j];

}
order[i] = 0;

}
n *= 10;
k = 0;
m++;
}
}

/**
* lsd from baidu
* @param data
*/
public void radixSort_LSD_2(int data[])//data为待排序数组
{
int n=data.length;
int bask[][]=new int[10]
;
int index[]=new int[10];
int max=Integer.MIN_VALUE;
for(int i=0;i<n;i++)
{
max=max>(Integer.toString(data[i]).length())?max:(Integer.toString(data[i]).length());
}

String str;
for(int i=max-1;i>=0;i--)
{
for(int j=0;j<n;j++)
{
str="";
if(Integer.toString(data[j]).length()<max)
{
for(int k=0;k<max-Integer.toString(data[j]).length();k++)
str+="0";
}
str+=Integer.toString(data[j]);
bask[str.charAt(i)-'0'][index[str.charAt(i)-'0']++]=data[j];
}
int pos=0;
for(int j=0;j<10;j++)
{
for(int k=0;k<index[j];k++)
{
data[pos++]=bask[j][k];
}
}
for(int x=0;x<10;x++)index[x]=0;
}
}


MSD(Most significant digital):

算法:

先按k1 排序分组,将序列分成若干子序列,同一组序列的记录中,关键码k1相等。

再对各组按k2 排序分成子组,之后,对后面的关键码继续这样的排序分组,直到按最次位关键码kd 对各子组排序后。

再将各组连接起来,便得到一个有序序列。

分析:

平均最好最坏辅助存储稳定性
O(d*(n+r))O(d*(n+r))O(d*(n+r))O(n+r)稳定
d为关键码个数,n为待排序元素个数,r为关键字取值基数

代码:

/**
* msd
* @param array
* @param begin
* @param end
* @param d
*/
void radixSort_MSD_1(int[] array,int begin,int end,int d){
if (d==0||begin==end) return;

int[][] temp = new int[10][array.length];
int[] order = new int[10];

int k = begin;

for (int i = begin; i <= end; i++) {
int lsd = d!=1?array[i]/(int) Math.pow(10,d-1):array[i]%10;
temp[lsd][order[lsd]++] = array[i];
}

for (int i = 0; i < 10; i++) {
if (order[i] == 0) continue;
for (int j = 0; j < order[i]; j++) {
array[k++] = temp[i][j];

}

//
radixSort_MSD_1(array,k - order[i],k-1,d-1);

}

}

三、桶排序:

算法:

将数组分到有限数量的桶子里。每个桶子再个别排序(有可能再使用别的排序算法或是以递归方式继续使用桶排序进行排序)

注意:

很多文章对于桶排序的理解是不到位的,比如百度百科中桶排序中的java代码是基数排序lsd的代码,我认为桶排序与计数和基数排序更像是父类和子类的关系,计数排序是仅一次分桶,适合数据分布集中的场景,而基数排序增加分桶次数,适合数据数据分散的场景。那么为什么会把三者归位一类呢?我认为计数和基数排序已经能够完成“桶排序父类”的大部分工作,桶排序也就被人们当作一种独立的能内嵌比较排序的非比较排序算法,应用于实践中。

分析:

平均最好最坏辅助存储稳定性
O(n+c) c=n*(logn-logm)O(n)O(n+c)O(n+m)稳定
d为关键码个数,n为待排序元素个数,r为关键字取值基数

代码:

/**
*
* @param array
* @param left
* @param right
*/
private void insertionSort(int array[], int left, int right) {

for (int i = left; i < right-1 ; i++) {

for (int j = i+1; j < right; j++) {

if (array[i]>array[j]){
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}

}

}

}

/**
*
* @param array
* @param c
*/
private void countingSort(int array[],int c[]){
int b[] = new int[array.length];

for (int i = 0; i < array.length; i++) {
c[array[i]/10]++;
}

for (int i = 1; i < c.length; i++) {
c[i] += c[i-1];
}

for (int i = 0; i < array.length; i++) {
b[--c[array[i]/10]]=array[i];
}

System.arraycopy(b,0,array,0,array.length);
}

/**
*
* @param array
* @param c
*/
private void bucketSort(int array[],int c[]){
countingSort(array,c);
insertionSort(array,0,c[0]);
for (int i = 1; i < c.length; i++) {
insertionSort(array,c[i-1],c[i]);
}

}


参考链接: http://www.cnblogs.com/eniac12/p/5332117.html#s1 http://blog.csdn.net/simongeek/article/details/45202173
如有错误,欢迎指出!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐