1. 程式人生 > >微軟筆試題——基數排序

微軟筆試題——基數排序

這是一題微軟的筆試題,原題如下:

 排序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] + " ");
		// }
	}
}