编程珠玑(一)

来源:互联网 发布:js获取指定日期前一天 编辑:程序博客网 时间:2024/05/21 22:28
1.如果不缺内存,如何使用一个具有库的语言来实现一种排序算法以表示和排序集合?
 在C语言中stdlib.h库中存在一个qsort()函数,此函数实现的是快速排序。
 函数的原型为:void qsort(void *base,int nelem,int width,int (*fcmp)(const void *,const void *));
参数:
1 待排序数组首地址
2 数组中待排序元素数量
3 各元素的占用空间大小
4 指向函数的指针,用于确定排序的顺序
#include <stdio.h>
#include <stdlib.h>
#define NUM 10
int compare(const int *a,const int *b ){
 return *(int *)a-*(int *)b;
}
void main(){
 int data[NUM]
 int i=0;
 while(i<NUM)
 scanf("%d\n",&data[i]);
 for(int j=0;j<NUM;j++)
 printf("%d",&data[j]);
 qsort(data,NUM,sizeof(data[0]),compare);
 for(int j=0;j<NUM;j++)
 printf("%d",data[j]);
}
在C++中我们以set<int>为例
#include <iostream> 
#include <set> 
#define NUM 5
using namespace std;


int _tmain(int argc, _TCHAR* argv[])
{
set<int> data;
int i = 0, x;
set<int>::iterator j;
while (i<NUM)
{
cin >> x;
data.insert(x);
i++;
}
for (j = data.begin(); j != data.end(); j++)
cout << *j << " ";
return 0;
}
java中我们也以ArrayList容器为例
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
public class setsort {
public static void main(String[] arg)
{
ArrayList<Integer> set=new ArrayList<Integer>();
set.add(21);
set.add(43);
set.add(65);
set.add(22);
set.add(12);
Collections.sort(set);
Iterator<Integer> iterator=set.iterator();
while(iterator.hasNext())
{ System.out.println(iterator.next());
}

}
}
2.如何使用位逻辑运算(例如与、或、移位)来实现向量?
磁盘文件排序问题: 1MB内存,磁盘中有一千万个整数(每个数都小于1千万,且无重复)。如何排序输出?
如果按照位运算的话,1MB=1024*1024*8=8388608个不同位,也就是说1MB的内存最多只能对八百多万个排序,如果实现一千万个整数,最少需要一千万/(1024*1024*8),要1M多。
采用整形数。总体相当于一个二维数组,每一个整形代表32位,即代表一行。总共有32列。例如34这个整数,存放的二维数组位置就是这么算的,
34/32=1在第二行(从0开始的话),34%32=2在第二个位置,故在第二行的第三列这一位数字置为1,公式即为 a[i/32] |=[1<<[i%32]] ,或许还有点不明白,再来解释一下这个公式:
右边是将1向左移动i%32位,右面是指i这个数所在的数组,其中还发现一个|符号,为什么要做或运算呢?我们就拿33与34做一下说明
初始化时二维数组每个值都为整数0,我们只看数组的前两个数,
0000 0000 0000 0000第一行a[0]
0000 0000 0000 0000第二行a[1]
当我们计算33时 33/32=1 ,所以在第二行 a[1]中,33%32=1,所以应该向左移一位,所以把33放入的话就变成了
0000 0000 0000 0000第一行a[0]
0000 0000 0000 0010第二行a[1]
继续来做34,那么很显然34也是在第二行,但要往左移动两位,所以先往左移动两位的话a[1]变为了0000 0000 0000 0100,那我们要怎么做才能保证我们
原来33的信息不被覆盖呢,所以要做 |(或)运算 来得到新的a[1]的值 0000 0000 0000 0110
那么理解了这个过程,可以把对32的操作换成操作二进制的位,那么除以32相当于右移5位,模32相当于与0X1F即0000 0000 0001 1111在这里需要32位,故我补全到32位了)相&。
所以可以如书上所写的方式:
#define BITSPERWORD 32
#define SHIFT 5
#define MASK 0X1F
#define N 100000000
int a[1+N/BITSPERWORD]
void set(int i){a[i>>SHIFT] |={1<<{i&MASK}};}//将i值所在位置1
void clr(int i){a[i>>SHIFT] &=~{1<<{i&MASK}};}//将i值所在位置0
int  test(int i){ return a[i>>SHIFT] &{1<<{i&MASK}};}//将i值所在位的值返回(0或者1)
3.按照2的思想进行排序,书中要求10000000个,为了节省时间我们可以换做其他的数值来做。
代码(参考书本)
#include<stdio.h>
#define BITSPERWORD 32
#define SHIFT 5
#define MASK 0X1F
#define N 100000000
void set(int i){a[i>>SHIFT] |={1<<{i&MASK}};}//将i值所在位置1
void clr(int i){a[i>>SHIFT] &=~{1<<{i&MASK}};}//将i值所在位置0
int  test(int i){ return a[i>>SHIFT] &{1<<{i&MASK}};}//将i值所在位的值返回(0或者1)
int main(){
int a[1+N/BITSPERWORD];
for(i=0;i<N;i++)
clr(i);
while(scanf("%d",&i)!=EOF)
set(i);
for(i=0;i<N;i++)
if(tset(i))
  printf("%d\n",i);
  return 0;
}
0 0