对1000000个数进行排序找出10个最大的数

原创 2006年05月30日 16:03:00

创建时间:2006年5月28
属性:原创
内容简介:快速排序,堆排序
关键字:快速排序,堆排序,排序


前序

从某网上看到google的面试题目,要求从1000000个数中选出10个最大的数,题目好像有些挑战性,想了半天,只知道用快速排序或堆排序或者归并排序比较好,于是开始动手写写。


一.随即生成数字(异常就懒得写了)

void CreateTheDataFile(long *&data, long &count)// data为引用一个指针,以便传回生成的数组
                                                                                           // count为data数组中数据的个数
{
 char num[9] = {'/0'};
 CFile file;
 if(!file.Open("num.dat",
  CFile::modeReadWrite |
  CFile::modeCreate |
  CFile::shareDenyNone |
  CFile::typeBinary))
  return;
 srand((long)time(NULL));
 for (int i = 0; i< 0xFFFFF; i++) //生成1000000个数字
 {
  int j = rand(); //随机生成数字
  int temp = j;
  int k = 0;   // 数字的位数
 
   if (j % 10 != 0)
  {
   for(;j % 10 != 0;) // 以下生成数字的位数
   {
    j /= 10;
    k++;
   }
  }
  else
  {
   for(;j > 0;) // 以下生成数字的位数
   {
    j /= 10;
    k++;
   }
  }
  j = temp;
  _itoa(j, num, 10);
  file.Write(num, k); // 只写k位数字
  file.Write("/n", 1);
 }
 /**/
 long *num2 = new long[0xFFFFFF]; //申请16M的空间,存储要比较的整数
 if (num2 == NULL)
  return;
 memset(num2, '/0', sizeof(num2));
 char num3[2048] = {'/0'};
 char num5[1][9]; // 存放字符串,表示一个整数字符串
 memset(num5[0], '/0', sizeof(num5));
 file.SeekToBegin();
 long i2 = 0, j = 0, k = 0;
 for (DWORD ii = 0; ii<=file.GetLength();)
 {
  if(!file.Read(num3, sizeof(num3)))
  return;
 
  for (i2 = 0 ; i2< sizeof(num3); i2++) // 把含有“/n”的字符给分离出来
  {
   if (num3[i2] != '/n') // 如果不是换行符,则是数字字符,把其提出来
    num5[0][j++] = num3[i2];
   else // 出现换行符,则表示提出来的字符完成了,应该转换成整数,
   {
    num2[k] = atoi(num5[0]);
    memset(num5[0], '/0', sizeof(num5)); // 清空,以便下次用
    k++;
    j = 0;
    continue;
   }
  }
   // 清空num3,以便正确统计k
  memset(num3, '/0', sizeof(num3));
  ii += sizeof(num3);
 }
 file.Close();
 data = num2;
 count = k;
}


二.快速排序和堆排序

考虑到快速排序用递归的时候可能导致栈溢出(即使设置编译参数调整默认堆栈大小大于1M也不行),只好用非递归算法了,关于堆排序很简单。以下为排序算法:

void QuickSort(long data[], long low, long high) // 非递归算法
{
 long pivotpos = low, i, j, ii = 0, jj = 0;
 long lo = 0, hi = 0;
 if (low < 0 || high <0 || low >= high)
  return;
 long **Qstack = new long*[2]; // 申请一个二维数组
 for(i = 0; i<2; i++)
 {
  Qstack[i] = new long[0xFFFFF];
 }
 Qstack[0][ii++] = low; // 记录低位数值
 Qstack[1][jj++] = high; // 记录高位数值
 long PivotNum = data[pivotpos];
 while(1)
 {
  lo = Qstack[0][--ii];
  hi = Qstack[1][--jj];
  i = lo;
  j = hi;
  PivotNum = data[lo];
  do
  {
   while(data[j] >= PivotNum && i < j) j--;
   if(i < j)
    data[i] = data[j];
   while(data[i] <= PivotNum && i < j) i++;
   if(i < j)
    data[j] = data[i];
  }while(i < j);
  data[i] = PivotNum; // 基准值对位
  pivotpos = i;
  /* // 对pivotpos的左边进行排序
  if(low < pivotpos - 1)
   QuickSort(num, low, pivotpos - 1);
  */
  if(lo < pivotpos - 1)
  {
   Qstack[0][ii++] = lo;
   Qstack[1][jj++] = pivotpos - 1;
  }
  /* // 对pivotpos的右边边进行排序
  if(pivotpos + 1 < high)
   QuickSort(num, pivotpos + 1, high);
  */
  if(pivotpos + 1 < hi)
  {
   Qstack[0][ii++] = pivotpos + 1;
   Qstack[1][jj++] = hi;
  }
  if (ii <= 0)
   break;
 }
 delete []Qstack[0];
 delete []Qstack[1];
}

void HeapSift(long data[], long i, long count)  // 堆筛选,对第i个数进行筛选,构造初始堆(大堆)
{
 long j = 2 * i +1;
 long temp = data[i];
 while(j <= count - 1)
 {
  if(i < count - 1 && data[j] < data[j + 1])
   j++;
  if(temp < data[j] )
  {
   data[i] = data[j];
   i = j;
   j = 2 * i + 1;
  }
  else
   break;
 }
 data[i] = temp; //找到位置,放回temp
}
void HeapSort(long data[], long count) // 堆排序
{
 long temp;
 long i = count / 2 - 1;
 for (; i >= 0; i--)
  HeapSift(data, i, count); //对每个数进行筛选
 for (i = 1; i <= count - 1; i++) //取出最大值,与堆尾的书进行交换
 {
  temp = data[0];
  data[0] = data[count - i];
  data[count - i] = temp;
  HeapSift(data, 0, count - i); //再进行筛选
 }
}


三.消息函数(我用的是MFC了,当然Win32也行)

消息映射就不写了,大同小异.
void OnQuickSort()
{
 long *data, count;
 long result[10];
 CreateTheDataFile(data, count); // 生成数据文件
 QuickSort(data, 0, count-1); // 开始排序
 OutPutTensMaxNums(data, result, count); // 输出结果
 delete []data;
}

void OnHeapSort()
{
 long *data, count;
 long result[10];
 CreateTheDataFile(data, count); // 生成数据文件
 HeapSort(data, count);
 OutPutTensMaxNums(data, result, count); // 输出结果
 delete []data;
}


四.输出结果(弹出对话框)

void OutPutTensMaxNums(long data[], long result[10], long CountOfNum)
{
 long pos = CountOfNum - 10;
 char ResultOfNum[9*10 + 1]; //存放显示的结果
 char ResultOfTemp[12];
 memset(ResultOfNum, '/0', sizeof(ResultOfNum));
 memset(ResultOfTemp, '/0', sizeof(ResultOfTemp));
 for (int i = 0; i< 10; i++)
 {
  result[i] = data[pos++];
  itoa(result[i], ResultOfTemp, 10);
  strcat(ResultOfNum, ResultOfTemp);
  strcat(ResultOfNum, "/n");
 }
 AfxMessageBox(ResultOfNum);
}


五.后记

1.经过测试,以上两个排序算法对1000000个数字进行完全排序大约要几秒钟的时间(cpu p4 2.6G),如果不生成数据文件存到硬盘中那就很省时,关键是生成数字存与读很浪费时间。当然由于自身功底的问题,我暂时还想不到用其他更好的算法(周末去书店看了半天 Donald E. Knuth的《The Art of Computer Programming》也没看懂,网上也找不到更合适的算法,呵呵)。感觉而言,HeapSort在此排序中比较快(无可厚非QuickSort的算法了,总体而言,这是最快的排序算法了!),如果只找出10个的的数字,那么HeapSort可能更快(QuickSort大概也行,我懒得想了,近来的了颈椎病,一考虑问题就头疼,特别是不能低着头看书或搞电脑,原谅!),QuickSort的递归算法只能排大约100个数字,否则就堆栈溢出(因为前面有些数据占用堆栈的空间较大),当然不是一个好的解决办法,非递归更好一些,但占用堆的空间较大,而HeapSort则好一点。MergeSort在这里没有写出,不知什么时间开销,DS书中都称这三个都差不多,而QuickSort更好一点。
2.代码运行中占用内存空间较大70M左右,这可能是个最烂的算法了,前面申请的内存空间太大了,当然有更高效的算法,时间关系就不想了,笨想法就用笨方法解决好了,暂时只是要个结果。
3.以上代码写的很乱,加上思考这个问题的时间零零散散,所以就没什么水平了,望看到这篇文章的各位原谅!


六.参考书目

1.《数据结构辅导与提高》徐孝凯,清华大学出版社
2.《数据结构(C语言版)》严蔚敏 吴伟民,清华大学出版社
3.《数据结构题集(C语言版)》严蔚敏 吴伟民,清华大学出版社)》
4.网络(这里不列出了)

相关文章推荐

(算法)从10000个数中找出最大的10个

从10000个整数中找出最大的10个,最好的算法是什么? 算法一:冒泡排序法   千里之行,始于足下。我们先不说最好,甚至不说好。我们只问,如何“从10000个整数中找出最大的10个”?我...

找出10个最大的文件并排序

当磁盘空间不够的时候,我们需要删除一些比较大的文件。如何找到这些大文件呢?下面的代码能够帮你实现import java.io.File; import java.util.ArrayList; imp...

N个数中找出最大的K个数

题目描述: 有很多个(N个)无序的数,我们姑且假定它们各不相等,怎么选出其中最大的若干个(k个)数呢? 1.N=100, K = 10的时候怎么处理? 2. N=1000, K = 100呢? ...

从一亿个数中找出最大的一万个数

问题定义:         从一亿个数中找出最大的一万个数 不假思索:         拿到这道题,马上就会想到的方法是建立一个数组把1亿个数装起来,然后用for循环遍历这个数组,找出最大的1万...
  • lalor
  • lalor
  • 2012年03月19日 13:18
  • 8570

100w个数中找出最大的前K个数

100w个数中找出最大的前K个数这个题是堆应用。 首先100万个数大约占4M内存,可以加载到内存中。我们可以采用排序解决这个问题,比如堆排序、快排等,但排序不是最优解。我们可以利用最小堆来解决这个问题...

N个数里面找出最大的k个数

题目:给出N个无序的数,然后找出其中最大的k个数 解题思路:          首先测试数据有可能会有一亿个数,数据量特别的大,数据库不可能存储这么多的数据。如果直接sort排序,NlogN时间复...

如何从100万个数中找出最大的前100个数

1.  算法如下:根据快速排序划分的思想  (1) 递归对所有数据分成[a,b)b(b,d]两个区间,(b,d]区间内的数都是大于[a,b)区间内的数  (2) 对(b,d]重复(1)操作,直到...
  • cslbupt
  • cslbupt
  • 2017年03月25日 11:37
  • 2501

从一亿个数中找出最大的一万个数

问题定义:         从一亿个数中找出最大的一万个数 不假思索:         拿到这道题,马上就会想到的方法是建立一个数组把1亿个数装起来,然后用for循环遍历这个数组,找...
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:对1000000个数进行排序找出10个最大的数
举报原因:
原因补充:

(最多只允许输入30个字)