对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.网络(这里不列出了)

从一个含有很多不同元素的大数组中寻找10个最大的数

第一次找工作面试的时候,面试
  • vinckyliu
  • vinckyliu
  • 2014年08月05日 00:25
  • 1094

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

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

java编程之对10个整数进行排序(从命令窗输入数据)

/* *对10个整数排序 */ import java.util.Scanner; class sort{ public static void main(String args[]){ S...
  • u010274673
  • u010274673
  • 2013年04月24日 14:41
  • 3245

10亿个数中找出最大的10000个数(top K问题)

前两天面试3面学长问我的这个问题(想说TEG的3个面试学长都是好和蔼,希望能完成最后一面,各方面原因造成我无比想去鹅场的心已经按捺不住了),这个问题还是建立最小堆比较好一些。先拿10000个数建堆,然...
  • will130
  • will130
  • 2015年11月04日 11:39
  • 1449

每天一道算法题(14)——N个降序数组,找到最大的K个数

题目:       假定有20个有序数组,每个数组有500个数字,降序排列,数字类型32位uint数值,现在需要取出这10000个数字中最大的500个。 思路       (1).建立大顶堆,维...
  • qianhen123
  • qianhen123
  • 2015年06月18日 10:38
  • 1078

用堆排序寻找数组中最大的K个数

/*********************************************************************************** 堆排序(Heapsort)是指...
  • shihui512
  • shihui512
  • 2013年04月22日 15:31
  • 1650

TOP-K排序算法,从海量不重复数据中找出最大/小的K个数

如题,TOP-K排序的主要功能是找出一堆不重复数据中的最小或最大的几个数,此处我们介绍这种类型题目的几种解法: 一.最大最小堆,最大堆结构里面的每一个数不都是小于root的值么?和我们要解决的问题很像...
  • u014403897
  • u014403897
  • 2015年04月23日 12:08
  • 1548

n个数里找出前m个数(或者 从10亿个浮点数中找出最大的1万个)

转载自:http://blog.csdn.net/winsunxu/article/details/6219376点击打开链接 引子 每年十一月各大IT公司都不约而同、争后恐后地到各大高校...
  • see__you__again
  • see__you__again
  • 2016年06月19日 20:22
  • 1061

n个数里面找出最大的m个数字(快排思想)

分析:这个问题,我之前遇到的时候想到的解决方案是,最小堆解决方法。建立个数为m的最小堆,然后遍历n维护这个最小堆就可以了,算法的时间复杂度是n*log(m)。还是比较高效的算法的。 今天我又...
  • liuyanfeier
  • liuyanfeier
  • 2016年08月31日 10:05
  • 1503

n个整数中找出连续m个数加和是最大Java版

即上一篇Python版取连续加和最大的整数后,本篇博客带来Java版取连续加和最大的整数。总体的思路入上一次博客中所述,就不在过多的阐述,关键就在于如何应用Java API写出相同逻辑的代码。 ...
  • qq_34122768
  • qq_34122768
  • 2017年10月30日 11:18
  • 113
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:对1000000个数进行排序找出10个最大的数
举报原因:
原因补充:

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