这是一个使用了斐波那契数列来完成排序的算法,由于使用了四条数组,我称它为DNA排序算法,
这个算法排序效率还是挺可以的,比Java 的arrays.sort()还快一些, 不过在内存占用率方面不及格;
public class DNA {
public static void main(String args[]) {
// 1,随机生成n个long范围的值,并将值存放到数组中
int n = 10000000;
long scope = 1000000000000000000L;
long[] arrA = new long[n];//0和1状态值
long[] arrT = new long[n];//锚点
long[] arrC = new long[n];//能量
long[] arrG = new long[n];//原始数据
for (int i = 0; i < n; i++) {
long m = (long) (Math.random() * scope);
arrG[i] = m;
}
// 4.找出数组arrM的最大值,循环之后,最大值跑到了数组的最后
long temp = 0;
for (int i = 0; i < n - 1; i++) {
if (arrG[i] > arrG[i + 1]) {
temp = arrG[i + 1];
arrG[i + 1] = arrG[i];
arrG[i] = temp;
}
}
// 5.生成斐波那契数组,给数组arrG盖楼,long类型的数总共可以盖93层
long[] arrN = new long[93];
long a = 1, b = 1;
for (int i = 1 ; a > 0; i += 2, a += b, b += a) {
arrN[i] = a;
arrN[i + 1] = b;
}
//System.out.println(Arrays.toString(arrN));
// 6.确定从哪一层开始工作
int level = 0;
for (int i = 0; i < 93; i++) {
if(arrN[92]<arrG[n-1]){
level=92;
}else if(arrN[i] >= arrG[n - 1]) {
level = i-1;
break;
}
}
// 7.给数组arrT初始锚点,用它来分隔单元
arrT[n - 1] = 8;
// 8.复制数组
for (int i = 0; i < n; i++) {
arrC[i] = arrG[i];
}
// 9.taget的作用是当数组arrT的状态值全部变为"8"的时候就结束楼层循环
int target=0;
// =====================开始历遍所有的楼层=======================
for (int i = level; i > 0; i--) {
if(target==n-1){
i=0;
continue;
}
// 准备数组arrA和数组arrC的数据,与之相比,arrT的数据是渐渐积累的
int aa = 0;
for (int j = 0; j < n; j++) {
arrA[j] = 0;
if (arrC[j] >= arrN[i]) {
arrC[j] -= arrN[i];
arrA[j] = 1;
aa++;
}
}
if(aa == 0){//aa的作用是当arrA的值全部相同的时候,直接跳过这一层循环
continue;
}
int begin = 0;
int end = 0;
int num = 0;
// ------------------这是一个楼层的开始---------------------
for (int j = 0; j < n; j++) {
if (arrT[j] == 0) {
num++;
continue;
} else if (num == 0) {
continue;
}
end = j;
begin = j - num;
// --------------这是一个单元的开始------------------
int mun1 = num;
int mun2 = num;
for (int z = begin; z <= end; z++) {
if (arrA[z] == 0) {
mun1--;
}else if (arrA[z] == 1) {
mun2--;
}
}
// 如果这个单元全部是0,或全部是1,就没必要往下走了,直接跳过这个单元
if (mun1 == -1 | mun2 == -1) {
num=0;//重新开始循环下一个单元,num的值要恢复初始值
continue;
}
/*
* 这是一个单元中有0和1的情况,大部分情况是这样子,这是程序最繁忙的地方
* 采用的方式是:从begin向右找"0",找到"0",就从end往左找"1",
* "0"和"1"配对,配对成功,就调换数据,数组arrA,arrC,arrG都需要调换
* 如此循环,直到配对失败,退出循环,然后再给数组arrT增加标记(即给下个楼层添加单元)
*/
uu: while (begin < end) {
if (arrA[begin] == 1) {
while (begin < end) {
if (arrA[end] == 0) {
temp = arrG[begin];
arrG[begin] = arrG[end];
arrG[end] = temp;
temp = arrC[begin];
arrC[begin] = arrC[end];
arrC[end] = temp;
temp = arrA[begin];
arrA[begin] = arrA[end];
arrA[end] = temp;
begin++;
continue uu;
}
end--;
}
begin--;//配对失败,说明这个位置只能是1,而不是0,所以要减1;
}
begin++;
}
arrT[begin - 1] = 8;//添加锚点
target++;
num = 0;
// ----------这是一个单元的结束--------------
}
// -----------------这是一个楼层的结束----------------
}
// =====================结束历遍所有的楼层=======================
//数据排序完成后,检查是否有错,有错就输出错误信息,没错就只输出数组
int dddd = 0;
for(int i=0; i<n-1; i++){
if(arrG[i+1]<arrG[i]){
dddd++;
System.out.println(arrG[i]+"-------"+dddd);
System.out.println(i);
System.out.println(arrG[i+1]);
System.out.println();
}
}
for(int i=1001;i<2100;i++){
if(i%10==0){
System.out.println();
}
System.out.print(arrG[i]+" ");
}
//System.out.println(Arrays.toString(arrG));
}
}