第一章 开篇

    《编程玑珠》中一些章节中有一些算法的实现,书后和网络上有源代码的例子,边看边学同时做一下记录。

如果不缺内存,如何使用一个具有库的语言来实现一种排序算法以表示和排序集合。

利用C语言中的qsort函数实现程序。

qsort函数是ANSI C标准中提供的,其声明在stdlib.h文件中,是根据二分法写的,其时间复杂度为n*log(n),其结构为:

void qsort(void *base, size_t nelem, size_t width, int (* comp)(const void *, const void *));

其中:

*base 为要排序的数组

nelem 为要排序的数组的长度

width 为数组元素的大小(一字节为单位)

默认的顺序是从小到大

(* comp)(const void *p1,const void *p2) 为判断大小函数的指针,这个函数需要自己定义,如果p1>p2,函数返回-1;a<b,函数返回1;a==b函数返回0。 

//Sort input set of integers using qsort
#include <stdio.h>
#include <stdlib.h>

int a[10000];

/*
int intcmp(int *x, int *y)
{
    return (*x-*y);
}
*/
int intcmp(const void *x, const void *y)
{
    return *(int *)x-*(int *)y; 
}

int main()
{
    int i, n=0;
    while(scanf("%d",&a[n])!=EOF)
        n++;
    qsort(a, n, sizeof(int), intcmp);
    for(i=0;i<n;i++)
        printf("%d ",a[i]);
        
    return 0;    
}

使用C++中的标准模板库中的set容器实现:

// Sort input set of integers using STL set
// set容器中每个元素的值必须惟一,而且系统会根据该值自动将数据排序 
#include <iostream>
#include <vector>
//#include <iterator>

using namespace std;

int main()
{
    int i;
    set<int> S;
    set<int>::iterator iset;
    while(cin>>i)
        S.insert(i);
    for(iset=S.begin();iset!=S.end();++iset)
        printf("%d ",*iset);
    /*
    while(*iset>0)
    {
                printf("%d ",*iset);
                ++iset;
    }
    */
    return 0;
}

使用位逻辑运算(例如与、或、移位)来实现位向量并编写程序实现位图排序,程序可以实现用10000000个bit位排序最多10000000个不同的正整数,其中每个正整数都小于10000000

使用一个数组存储数据,其中数组每一位模拟块32bit位的内存空间(1MB大概是8000000bit位),使用位运算将代表数据的某一位设置为0或1,其实是一个输入数据到位图的转换程序。注意其中的位运算符的结合性都是自左向右。程序设置了3个函数,分别完成置1,清0和检测的功能。

// Bitmap sort
// Sort distinct integers in the range [0...N-1]
#include <stdio.h>
#define BITSPERWORD 32
#define N 10000000
int a[1+N/BITSPERWORD];

//void set(int i){a[i/BITSPERWORD]|=((i%BITSPERWORD)<<1);}
void set(int i){a[i/BITSPERWORD]|=(1<<(i%BITSPERWORD));}
//void clr(int i){a[i/BITSPERWORD]&=~((i%BITSPERWORD)<<1);}
void clr(int i){a[i/BITSPERWORD]&=~(1<<(i%BITSPERWORD));}
//int test(int i){return a[i/BITSPERWORD]&((i%BITSPERWORD)<<1);}
int test(int i){return a[i/BITSPERWORD]&(1<<(i%BITSPERWORD));}

int main()
{
    int i;
    for(i=0;i<N;i++)        
        clr(i);
    while(scanf("%d",&i)!=EOF)
        set(i);
    for(i=0;i<N;i++)
        if(test(i))
            printf("%d ",i);
            
    return 0;
}

程序是包括0在内的,所以题目的准确描述是10000000个不同的非负整数,每个非负整数都小于10000000。上面的程序是按照移位的思路写下来的,但源程序有另外两个宏变量:SHIFT,MASK。功能是一样的,上面的程序给的函数形参是按照十进制处理的,在多加宏变量的情况下是按照二进制处理的(不太好理解)。主函数相同。

#define BITSPERWORD 32
#define SHIFT 5
#define MASK 0x1F
#define N 10000000
int a[1 + N/BITSPERWORD];

void set(int i) {        a[i>>SHIFT] |=  (1<<(i & MASK)); }
void clr(int i) {        a[i>>SHIFT] &= ~(1<<(i & MASK)); }
int  test(int i){ return a[i>>SHIFT] &   (1<<(i & MASK)); }

如何生成位于0至n-1之间的k个不同的随机顺序的随机整数?尽量使你的程序简短且高效。

思路是初始化一个有序的n元数组,利用函数生成一个从0到n-1的随机数,从0开始循环k次,每次将当前数组下标值数据与该随机数标注的数组下标值数据交换,从而生成k个不同的随机数。生成随机数的函数用到stdlib库中的rand()。

// get k distinct numbers in the range [0...n-1]

#include <stdio.h>
#include <time.h>
#include <stdlib.h>    //for rand(),srand(),atoi() 

#define MAXN 200000

int x[MAXN];

// generate a random integer between a and b (including a and b)
int randint(int a, int b)
{
    //return a+(RANDMAX*rand()+rand())%(b+1-a);
    return a+(RAND_MAX*rand()+rand())%(b+1-a);
} 

int main(int argc, char *argv[])
{
    int i,k,n,p,t;
    k=atoi(argv[1]);
    n=atoi(argv[2]);
    //srand(time(NULL));
    srand((unsigned) time(NULL));
    //  
    for(i=0;i<n;i++)
        x[i]=i;
    for(i=0;i<k;i++)
    {
                    t=randint(i,n-1); 
                    p=x[i];
                    x[i]=x[t];
                    x[t]=p;
    }
    for(i=0;i<k;i++)
        printf("%d\n",x[i]);
  
    return 0;
}

参考资料:

C语言qsort部分:http://hi.baidu.com/zfsuan/blog/item/07a6ab1e45f6fcd8a6866952.html

位运算符的结合性:http://blog.youkuaiyun.com/qiuyang0607/article/details/6789358

rand()与srand()函数:http://blog.sina.com.cn/s/blog_5fe506110100d4ne.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值