在http://blog.csdn.net/hongyuan19/archive/2007/11/16/1887656.aspx看到《关于一道1到N自然数排序的华为面试题》,文中提到了一道华为面试题:
有N个大小不等的自然数(1--N),请将它们由小到大排序。
要求程序算法:时间复杂度为O(n),空间复杂度为O(1)。
文中同时给出了该题的解法,但是从评论来看,还是有很多人不明白不理解。
本人写了一段的程序,给出了这道题完整的程序以及验证程序,该程序在VS2005下执行通过;
同时,本人在注释中给出了关于时间复杂度的简单证明,欢迎大家拍砖。
#include "stdafx.h" #include <stdio.h> #include <stdlib.h> #include <time.h> #include <string.h> #define SCRAMBLING_TIME (100) #define ARRAY_SIZE (100) //复杂度验证 int g_swap_time = 0; //swap操作执行次数 int g_while_time = 0; //while执行次数 //数组排序 void sort(int arr[], int n) { int t; /*临时变量:空间复杂度O(1)*/ //计算while条件执行次数,可知时间复杂度为O(n) //可证明swap_time < n; while_time = swap_time + n < 2n for (int i = 0; i < n; i++) { g_while_time ++; while(arr[i] != i + 1) { /* 证明!!!! 每次交换必然将一个数字正确安排到位,而退出循环的交换(条件arr[i] == i + 1)使2个数字安排到位; 就一次循环整体来看,m次交换导致m+1个数字到位,故swap_time < n, 继而while_time = swap_time + n < 2n,继而时间复杂度为O(n)。 */ //arr[i] 与 arr[arr[i] - 1]交换 t = arr[arr[i] - 1]; arr[arr[i] - 1] = arr[i]; //arr[arr[i] - 1]放入正确数字 arr[i] = t; g_swap_time ++; g_while_time ++; } } } void print_array(int arr[], int n) { for (int i = 0; i < n; i ++) { if (i % 10 == 0) { printf("/n"); } printf("%5d", arr[i]); } printf("/n"); } //生成顺序数组 void make_order_array(int arr[], int n) { for(int i = 0; i < n; i ++) { arr[i] = i + 1; } } //生成乱序数组 void make_scrambling_array(int arr[], int n) { make_order_array(arr, n); srand((unsigned int)time(NULL)); for (int i = 0; i < SCRAMBLING_TIME; i ++) { int pos1 = rand() % n; int pos2 = rand() % n; int t; t = arr[pos1]; arr[pos1] = arr[pos2]; arr[pos2] = t; } } int _tmain(int argc, _TCHAR* argv[]) { int array[ARRAY_SIZE] = {0}; make_scrambling_array(array, ARRAY_SIZE); printf("/noriginal array:/n"); print_array(array, ARRAY_SIZE); sort(array, ARRAY_SIZE); printf("/nsorted array:/n"); print_array(array, ARRAY_SIZE); int array_check[ARRAY_SIZE] = {0}; make_order_array(array_check, ARRAY_SIZE); if (0 == memcmp((void *)array, (void *)array_check, sizeof(array))) { printf("/n SORT ARRAY SUCC!!!!!!!/n"); } else { printf("/n SORT ARRAY FAIL!!!!!!!!/n"); } printf("/n while_time = %d/n", g_while_time); //验证while_time = swap_time + n < 2n printf("/n swap_time = %d/n", g_swap_time); //验证swap_time < n return 0; }
最后提一下,有些人认为这道题没意义,既然是元素1-N,干嘛还排序,直接按顺序重写数组不就拉倒了。
e.g
for (int i = 0; i < n; i ++)
{
a[i] = i + 1;
}
so easy,
但是——
我们假设1-N只是一个结构体的key,那我们肯定就不能这么简单处理,而是需要利用key对这个struct数组进行排序,如此,这个题目是不是就有点意义了?