这是一题微软的笔试题,原题如下:
排序N个比N^7小的数,要求的算法是O(n)(给了提示..说往N进制那方面想)
此题的分析见 http://blog.csdn.net/sinshine/article/details/6844370
本人使用了N进制的做法,当然在程序中涉及到了十进制字符串转化为N进制的整数(一个数组)和N进制整数转化为十进制字符串。修改之后的算法复杂度是O(n)级别的,因为将一个十进制整数字符串转化为N进制的整数是常数的(注意在本题中整数最大为N^7,表示为N进制最大7位),因此N个数的转化是O(n),而进行排序最多为7趟,每趟为O(n),因此算法总复杂度约为O(7*N)。
具体代码如下:
public class BaseSort {
// 排序N个比N^7小的数,要求的算法是O(n)
public static void sort(String[] strings) {
if (strings.length <= 1) {
return;
}
int n = strings.length;
Vector<List<int[]>> vector = new Vector<List<int[]>>();
// 构建n个桶
for (int i = 0; i < n; i++) {
vector.add(new ArrayList<int[]>());
}
// 将输入字符串转换为N进制整数
Vector<int[]> results = StringTen2IntegerN(strings, n);
int max = 0;
for (int j = 0; j < n; j++) {
if (max < results.get(j).length) {
max = results.get(j).length;
}
}
for (int i = 0; i < max; i++) {
for (int j = 0; j < n; j++) {
int[] integer = results.get(j);
if (integer.length <= i) {
vector.get(0).add(integer);
} else {
vector.get(integer[integer.length - i - 1]).add(integer);
}
}
results.clear();
for (int j = 0; j < n; j++) {
for (int j2 = 0; j2 < vector.get(j).size(); j2++) {
results.add(vector.get(j).get(j2));
}
vector.get(j).clear();
}
}
for (int i = 0; i < n; i++) {
strings[i] = n2Ten(results.get(i), n);
}
}
/**
* 将字符串数组转化为N进制的整数数组
*/
private static Vector<int[]> StringTen2IntegerN(String[] strings, int n) {
Vector<int[]> vector = new Vector<int[]>();
for (int i = 0; i < strings.length; i++) {
vector.add(Ten2N(strings[i].toCharArray(), n));
}
return vector;
}
/**
* 将任意长度的十进制字符串转换为n进制的整数
*
* @param csstrten
* @param n
* @return
*/
public static int[] Ten2N(char[] csstrten, int n) {
int istdeclen = csstrten.length; // 存储十进制串的长度
int k = 1; // 存储所有十进制串数码或运算的值,如果为0表示十进制数码串为0串
int quotient = 0; // 存储余数
int strten2NLen = 0; // N进制串的长度
int i, j; // 循环下标
int[] strten2N = new int[100];//这里的100其实在本程序中只需要7即可
int[] intdecten = new int[istdeclen];
for (i = 0; i < istdeclen; i++) { // 将十进制串转换为数字码并存储到临时空间中去
intdecten[i] = csstrten[i] - '0';
}
int tempsum = 0;
for (i = 0; k != 0; i++) { // 结束条件为被除数为0
for (j = 0; j < istdeclen; j++) {
k = 0;
while (j < istdeclen) { // 把十进制串前面的0过滤掉,不用每次都对十进制串前面的0进行计算
k += intdecten[j];
if (k != 0) {
k = 0;
break;
}
j++;
}
if (j == istdeclen) {
break;
}
tempsum = intdecten[j];
while (tempsum < n && j < istdeclen - 1) {
intdecten[j] = 0;
tempsum = tempsum * 10 + intdecten[++j];
}
quotient = (tempsum % n); // 求数码除以n的余数,关键
intdecten[j] = tempsum / n; // 求数码除以n的商,关键
if (j != istdeclen - 1) { // 如果j不是指向最后一位,那位将上一位的余数乘以10加进下一个数去
intdecten[j + 1] = (intdecten[j + 1] + quotient * 10);
}
}
k = 0;
for (int tt = 0; tt < istdeclen; tt++) {
if (intdecten[tt] != 0) {
k = 1;
break;
}
}
strten2N[i] = quotient; // 除n取余,把所得的余数存储起来,实际上存储的是数字码,关键
strten2NLen++; // N进制串的长度加1
}
int[] result = new int[strten2NLen];
for (int l = 0; l < strten2NLen; l++) {
result[l] = strten2N[strten2NLen - l - 1];
}
return result;
}
/**
* 将n进制的整数转化为十进制的字符串
*/
public static String n2Ten(int[] csstrN2ten, int n) {
int istrtwo2tenlen = csstrN2ten.length; // 存储n进制串的长度
int istrtwo2tendeclen = 1; // 默认十进制串的长度至少为1
int i, j; // 循环下标
int[] strtwo2tendec = new int[100];
// 该循环完成将n进制数码转换为十进制数码的工作,每取一位n进制数,对应的十进制数要乘以n并加上所取的n进制数
for (i = 0; i < istrtwo2tenlen; i++) {
for (j = 0; j < istrtwo2tendeclen; j++) {
strtwo2tendec[j] *= n; // 每一位十进制数乘n
}
strtwo2tendec[0] += csstrN2ten[i]; // 十进制数个位加上取得的十进制数
for (j = 0; j < istrtwo2tendeclen || strtwo2tendec[j] >= 10; j++) {
strtwo2tendec[j + 1] += strtwo2tendec[j] / 10; // 将每一位的前一位分离出十位,前把它加到该位来
strtwo2tendec[j] %= 10; // 该位被分离后,保留个位不变
}
istrtwo2tendeclen = j + 1; // 如果进来的十进制位使对应十进制数长度增加1
}
StringBuffer sBuffer = new StringBuffer();
for (int l = istrtwo2tendeclen - 1; l >= 0; l--) {
sBuffer.append(strtwo2tendec[l]);
}
return sBuffer.toString();
}
public static void main(String[] args) {
String[] strings = new String[100000];
int max = (int) Math.pow(100000, 7);
for (int i = 0; i < strings.length; i++) {
int temp = new Random().nextInt(max);
strings[i] = String.valueOf(temp);
}
// for (int i = 0; i < strings.length; i++) {
// System.out.print(strings[i] + " ");
// }
// System.out.println();
System.out.println("开始排序!" + System.currentTimeMillis() / 1000);
sort(strings);
System.out.println("完成排序!" + System.currentTimeMillis() / 1000);
// for (int i = 0; i < strings.length; i++) {
// System.out.print(strings[i] + " ");
// }
}
}