习题 1. 如果不缺内存,如何使用一个具有库的语言来实现一种排序算法以表示和排序集合?
由于目前只学习了C和C++,所以只讨论C和C++中具有排序算法的库。对于C,有stdlib.h中的快速排序qsort函数;对于C++,其STL中的algorithm包含的一个排序算法sort函数。
#include <stdlib.h> void qsort( void *buf, size_t num, size_t size, int (*compare)(const void *elem1, const void *elem2 ));
#include <stdlib.h> #include <iostream> using namespace std; int compare(const void * elem1, const void * elem2) { if (*(int *)elem1 < *(int *)elem2) { return -1; //若需要按降序排列,这里返回1 } else if (*(int *)elem1 == *(int *)elem2) { return 0; } else { return 1; //若需要按降序排列,这里返回-1 } } int _tmain(int argc, _TCHAR* argv[]) { int num[]={49, 38, 60 , 90 , 70, 15, 30, 49}; int len = sizeof(num) / sizeof(int); qsort(num, len, sizeof(int), compare); for (int i = 0; i < len; i++) { cout<< num[i]<<" "; } cout << endl; return 0; }
输出结果:15 30 38 49 49 60 70 90
C++ STL中的排序算法sort函数:
template <class RandomAccessIterator> void sort ( RandomAccessIterator first, RandomAccessIterator last ); template <class RandomAccessIterator, class Compare> void sort ( RandomAccessIterator first, RandomAccessIterator last, Compare comp );
#include <iostream> #include <algorithm> #include <vector> using namespace std; bool myFunction(int i, int j) { return i < j; //若要降序排序则return i > j; } class myClass { public: bool operator() (int i, int j) { return i < j; //若要降序排序则return i > j; } }; int _tmain(int argc, _TCHAR* argv[]) { int num[]={49, 38, 60 , 90 , 70, 15, 30, 49}; vector<int> myVector(num, num + 8); vector<int>::iterator it; myClass myObject; //函数对象 // using default comparison (operator <): sort(myVector.begin(), myVector.begin() + 4); //(38 49 60 90) 70 15 30 49 // using default comparison (operator <): sort(myVector.begin() + 4, myVector.end()); //38 49 60 90 (15 30 49 70) // using function as comp: sort (myVector.begin(), myVector.end(), myFunction); //(15 30 38 49 49 60 70 90) for (it = myVector.begin(); it != myVector.end(); it++) { cout<< *it<<" "; } cout << endl; vector<int> myVector2(num, num + 8); //using object as comp: sort(myVector2.begin(), myVector2.end(), myObject); //(15 30 38 49 49 60 70 90) for (it = myVector2.begin(); it != myVector2.end(); it++) { cout<< *it<<" "; } cout << endl; return 0; }
对于一个int型变量其大小为4字节,一个字节等于8bits,随意一个int型变量占32bits。可以充分利用这32个位,利用一个int型变量即可表示一个所有元素都小于32([0, 32))的非负整数的集合。
例如,对于集合A={0,4,8,15,21,28}, 用int a来表示该集合,则有:
a的二进制表示为: 10001000100000010000010000001000,其实十进制为 a = 2290156552
int bitArry[312500]; //用int型数组来模拟位数组,具有1000 0000个位,初始的时候将每个位置为false
#include <iostream> #include <stdlib.h> using namespace std; #define BITSPERDWORD 32 //表示一个整形变量具有32个位 #define SHIFT 5 //单次位移量,右移一位相当于除以2,左移一位相当于乘以2 #define MASK 0x1f //掩码,其十进制即为31 #define N 10000000 //表示10000000个7为非负整数 //将位数组从0开始的第i个位置为0 void reset(int * arry, int i) { arry[i >> SHIFT] &= ~(1 << (i & MASK)); //m%n,n = 2^x时,m%n = m & (n-1) } //将位数组从0开始的第i个位置为1 void set(int * arry, int i) { arry[i >> SHIFT] |= (1 << (i & MASK)); } //检测i是否在集合中 int test(int * arry, int i) { return arry[i >> SHIFT] & (1 << (i & MASK)); } int _tmain(int argc, _TCHAR* argv[]) { int arry[1 + N / BITSPERDWORD]; //加1是因为N不一定被BITSPERDWORD整除 int i; for (i = 0; i < N; i++) { reset(arry, i); } /*对位数组的初始置位0操作可以这样写: int size = 1+ N / 32; for (i =0; i < size; i++) { arry[i] = 0; } */ while (scanf("%d", &i) != EOF) { set(arry, i); } for (i = 0; i < N; i++) //从0到n-1,检测i是否出现过,若出现过则输出,若没有出现则不输出。 { //由于i从0到n-1递增,所以数据输出后便自动排好了序 if (test(arry, i)) { cout<<i; } } return 0; }
#include <stdlib.h> srand((unsigned)time(NULL));
//rand()通常返回约15个随机位,其最大值为RAND_MAX = 0x7fff。 //bigrand()则至少返回30个随机位 int bigrand() { return RAND_MAX * rand() + rand(); }
//返回[l, u]范围内的一个随机整数 int randint(int l, int u) { return (l + rand() % (u - l + 1)); }
//产生m个小于n的随机整数, 该函数直接利用bigrand()返回的随机对n求模 //即可得到[0, n)之间的随机数(可能有重复) void geneRand1(int m , int n) { int i = 0; srand((unsigned)time(NULL)); while (i < m) { cout << bigrand() % n << endl; i++; } }
//把包含整数0~n-1的数组顺序打乱,然后把前m个元素排序输出。 //即首先生成0~n-1的整数数组,然后产生随机数索引,引用该索引取出对应的数组元素。 //数组的前m个元素即为生成的随机数(无重复)。 void geneRand2(int m ,int n) { int i; int *pArry = new int[n]; for (i = 0; i < n; i++) //生成数组 { pArry[i] = i; } //筛选随机数 srand((unsigned)time(NULL)); for (i = 0; i < m; i++) { j = randint(i, n - 1); int t = pArry[i]; pArry[i] = pArry[j]; pArry[j] = t ; } delete [] pArry; }
template < class Key, class Compare = less<Key>, class Allocator = allocator<Key> > class set;
#include <stdlib.h> #include <time.h> #include <iostream> #include <set> #include <boost/timer.hpp> #include <boost/progress.hpp> using namespace std; using namespace boost; //返回[l, u]范围内的一个随机整数 int randint(int l, int u) { return (l + rand() % (u - l + 1)); } //函数对象类 class comp { public: bool operator ()(int i,int j) { if (i < j) //若要降序排列,则i > j { return true; } else { return false; } } }; int * geneRand2(int m ,int n) { int i, j; int *pArry = new int[n]; for (i = 0; i < n; i++) //生成数组 { pArry[i] = i; } //筛选随机数 srand((unsigned)time(NULL)); for (i = 0; i < m; i++) { j = randint(i, n - 1); int t = pArry[i]; pArry[i] = pArry[j]; pArry[j] = t ; } return pArry; } void mySort(int m ,int n) { set<int,comp> s; int i = 0; int * p = geneRand2(m ,n); progress_timer t; while (s.size() < (set<int,comp> ::size_type)m) { s.insert(p[i]); i++; } cout << t.elapsed()<<endl; // 生成位于0至n-1之间m个有序且不重复的随机整数所用的时间 delete [] p; } int _tmain(int argc, _TCHAR* argv[]) { mySort(1000000,10000000); return 0; }
#include <stdlib.h> #include <time.h> #include <iostream> #include <algorithm> #include <boost/timer.hpp> #include <boost/progress.hpp> using namespace std; using namespace boost; //返回[l, u]范围内的一个随机整数 int randint(int l, int u) { return (l + rand() % (u - l + 1)); } int * geneRand2(int m ,int n) { int i, j; int *pArry = new int[n]; for (i = 0; i < n; i++) //生成数组 { pArry[i] = i; } //筛选随机数 srand((unsigned)time(NULL)); for (i = 0; i < m; i++) { j = randint(i, n - 1); int t = pArry[i]; pArry[i] = pArry[j]; pArry[j] = t ; } return pArry; } void mySort(int m ,int n) { int i; int * p = geneRand2(m ,n); progress_timer t; sort(p, p + m); cout << t.elapsed()<<endl; // 生成位于0至n-1之间m个有序且不重复的随机整数所用的时间 delete [] p; } int _tmain(int argc, _TCHAR* argv[]) { mySort(1000000,10000000); return 0; }
第三种方法:采用位向量排序法。代码如下:
#include <stdlib.h> #include <time.h> #include <iostream> #include <boost/timer.hpp> #include <boost/progress.hpp> using namespace std; using namespace boost; #define BITSPERDWORD 32 //表示一个整形变量具有32个位 #define SHIFT 5 //单次位移量,右移一位相当于除以2,左移一位相当于乘以2 #define MASK 0x1f //掩码,其十进制即为31 #define N 10000000 //表示10000000个7为非负整数 //将位数组从0开始的第i个位置为0,即将整数i在位向量中对应位置的位置为false void resetBits(int * arry, int i) { arry[i >> SHIFT] &= ~(1 << (i & MASK)); //m%n,n = 2^x时,m%n = m & (n-1) } //将位数组从0开始的第i个位置为1,即将整数i在位向量中对应位置的位置为true void setBits(int * arry, int i) { arry[i >> SHIFT] |= (1 << (i & MASK)); } //检测i是否在集合中 int testBits(int * arry, int i) { return arry[i >> SHIFT] & (1 << (i & MASK)); } //返回[l, u]范围内的一个随机整数 int randint(int l, int u) { return (l + rand() % (u - l + 1)); } int * geneRand2(int m ,int n) { int i, j; int *pArry = new int[n]; for (i = 0; i < n; i++) //生成数组 { pArry[i] = i; } //筛选随机数 srand((unsigned)time(NULL)); for (i = 0; i < m; i++) { j = randint(i, n - 1); int t = pArry[i]; pArry[i] = pArry[j]; pArry[j] = t ; } return pArry; } void mySort(int m ,int n) { int i, j; int *pBitsArry = new int[1 +n / BITSPERDWORD]; int * p = geneRand2(m ,n); progress_timer t; for (i = 0; i < n; i++) { resetBits(pBitsArry, i); } for (i = 0; i < m; i++) { setBits(pBitsArry, p[i]); } for (i = 0, j = 0; i < n; i++) { if (testBits(pBitsArry, i)) { p[j++] = i; } } cout << t.elapsed()<<endl; // 生成位于0至n-1之间m个有序且不重复的随机整数所用的时间 delete [] p; delete [] pBitsArry; } int _tmain(int argc, _TCHAR* argv[]) { mySort(1000000,10000000); return 0; }
三种排序方法的时间效率如下图所示:
由图可以看出采用位向量方法使排序时间大大减少,程序效率有了质的飞跃!!!
转自:http://blog.csdn.net/silenough/article/details/6956758