算法一:

二分搜索算法(折半查找)原理以及递归(recuition),迭代(iteration)的两种实现源代码

By Minidxer | February 3, 2008

 

 

折半查找法也称为二分查找法,它充分利用了元素间的次序关系,采用分治策略,可在最坏的情况下用O(log n)完成搜索任务。

 

【基本思想】

 

n个元素分成个数大致相同的两半,取a[n/2]与欲查找的x作比较,如果x=a[n/2]则找到x,算法终止。如果x<a[n/2],则我们只要在数组a的左半部继续搜索x(这里假设数组元素呈升序排列)。如果x>a[n/2],则我们只要在数组a的右半部继续搜索x

 

二分搜索法的应用极其广泛,而且它的思想易于理解。第一个二分搜索算法早在1946 年就出现了,但是第一个完全正确的二分搜索算法直到1962年才出现。Bentley在他的著作《Writing Correct Programs》中写道,90%的计算机专家不能在2小时内写出完全正确的二分搜索算法。问题的关键在于准确地制定各次查找范围的边界以及终止条件的确定,正确地归纳奇偶数的各种情况,其实整理后可以发现它的具体算法是很直观的。

 

 

 

C++描述

 

Download: BinarySearch.cpp

template<class Type>

int BinarySearch(Type a[],const Type& x,int n) 

{ 

int left=0;

int right=n-1;

while(left<=right){ 

int middle=(left+right)/2;

if (x==a[middle]) return middle;

if (x>a[middle]) left=middle+1;

else right=middle-1;

} 

return -1;

}

递归实现(recuition

 

Download: binary_search_recuition.cpp

template<class Record, class Key>

int binary_search( Record * r, const int & low, const int & high, const Key & k )

{

int mid = (low + high)/2;

if( low < high )

{

  if( k <= r[mid] )

   binary_search( r, low, mid, k ); 

  else

   binary_search( r, mid+1, high, k );

}

else if( low == high )

{

  if( k == r[mid] )

   return low;

  else

   return -1;

}

else

  return -1;

}

迭代实现(iteration

 

Download: binary_search_iteration.cpp

template<typename Record, typename Key>

int binary_search( Record * r, const int & size, const Key & k )

{

int low=0, high=size-1, mid;

while( low < high )

{

  mid = (low + high) / 2;

  if( k > r[mid] )

   low = mid + 1;

  else

   high = mid;

}

if( low > high )

  return -1;

else

{

  if( k == r[low] )

   return low;

  else

   return -1;

}

}

 

算法二:

蚁群算法ACO(ant colony optimization)的原理以及实现源代码

By Minidxer | February 1, 2008

 

 

 之前说的算法基本上都比较枯燥的(废话,算法都很枯燥……),这次要介绍的蚁群算法(Ant Colony Algorithm)却是一种源于自然现象的算法,也是一种 meta heuristic,即与具体问题关系不大的优化算法,也就是它是一种用来在图中寻找优化路径的机率型技术。Marco Dorigo1992年在他的博士论文中引入,其灵感来源于蚂蚁在寻找食物过程中发现路径的行为。

 

 

 

小小的蚂蚁总是能够找到食物,他们具有什么样的智能呢?设想,如果我们要为蚂蚁设计一个人工智能的程序,那么这个程序要多么复杂呢?首先,你要让蚂蚁能够避开障碍物,就必须根据适当的地形给它编进指令让他们能够巧妙的避开障碍物,其次,要让蚂蚁找到食物,就需要让他们遍历空间上的所有点;再次,如果要让蚂蚁找到最短的路径,那么需要计算所有可能的路径并且比较它们的大小,而且更重要的是,你要小心翼翼的编程,因为程序的错误也许会让你前功尽弃。这是多么不可思议的程序!太复杂了,恐怕没人能够完成这样繁琐冗余的程序。

 

为什么这么简单的程序会让蚂蚁干这样复杂的事情?答案是:简单规则的涌现。事实上,每只蚂蚁并不是像我们想象的需要知道整个世界的信息,他们其实只关心很小范围内的眼前信息,而且根据这些局部信息利用几条简单的规则进行决策,这样,在蚁群这个集体里,复杂性的行为就会凸现出来。这就是人工生命、复杂性科学解释的规律!

 

下面就是实现如此复杂性的七条简单规则:

 

1、范围:

蚂蚁观察到的范围是一个方格世界,蚂蚁有一个参数为速度半径(一般是3),那么它能观察到的范围就是3*3个方格世界,并且能移动的距离也在这个范围之内。

2、环境:

蚂蚁所在的环境是一个虚拟的世界,其中有障碍物,有别的蚂蚁,还有信息素,信息素有两种,一种是找到食物的蚂蚁洒下的食物信息素,一种是找到窝的蚂蚁洒下的窝的信息素。每个蚂蚁都仅仅能感知它范围内的环境信息。环境以一定的速率让信息素消失。

3、觅食规则:

在每只蚂蚁能感知的范围内寻找是否有食物,如果有就直接过去。否则看是否有信息素,并且比较在能感知的范围内哪一点的信息素最多,这样,它就朝信息素多的地方走,并且每只蚂蚁多会以小概率犯错误,从而并不是往信息素最多的点移动。蚂蚁找窝的规则和上面一样,只不过它对窝的信息素做出反应,而对食物信息素没反应。

4、移动规则:

每只蚂蚁都朝向信息素最多的方向移,并且,当周围没有信息素指引的时候,蚂蚁会按照自己原来运动的方向惯性的运动下去,并且,在运动的方向有一个随机的小的扰动。为了防止蚂蚁原地转圈,它会记住最近刚走过了哪些点,如果发现要走的下一点已经在最近走过了,它就会尽量避开。

5、避障规则:

如果蚂蚁要移动的方向有障碍物挡住,它会随机的选择另一个方向,并且有信息素指引的话,它会按照觅食的规则行为。

7、播撒信息素规则:

每只蚂蚁在刚找到食物或者窝的时候撒发的信息素最多,并随着它走远的距离,播撒的信息素越来越少。

 

下面的程序开始运行之后,蚂蚁们开始从窝里出动了,寻找食物;他们会顺着屏幕爬满整个画面,直到找到食物再返回窝。

 

其中,‘F’点表示食物,‘H’表示窝,白色块表示障碍物,‘+’就是蚂蚁了。

 

参数说明:

最大信息素:蚂蚁在一开始拥有的信息素总量,越大表示程序在较长一段时间能够存在信息素。信息素消减的速度:随着时间的流逝,已经存在于世界上的信息素会消减,这个数值越大,那么消减的越快。

错误概率表示这个蚂蚁不往信息素最大的区域走的概率,越大则表示这个蚂蚁越有创新性。

速度半径表示蚂蚁一次能走的最大长度,也表示这个蚂蚁的感知范围。

记忆能力表示蚂蚁能记住多少个刚刚走过点的坐标,这个值避免了蚂蚁在本地打转,停滞不前。而这个值越大那么整个系统运行速度就慢,越小则蚂蚁越容易原地转圈。

 

源代码如下:

 

/*ant.c*/

 

#define SPACE 0x20

#define ESC 0x1b

#define ANT_CHAR_EMPTY '+'

#define ANT_CHAR_FOOD 153

#define HOME_CHAR 'H'

#define FOOD_CHAR 'F'

#define FOOD_CHAR2 'f'

#define FOOD_HOME_COLOR 12

#define BLOCK_CHAR 177

 

#define MAX_ANT 50

#define INI_SPEED 3

#define MAXX 80

#define MAXY 23

#define MAX_FOOD 10000

#define TARGET_FOOD 200

#define MAX_SMELL 5000

#define SMELL_DROP_RATE 0.05

#define ANT_ERROR_RATE 0.02

#define ANT_EYESHOT 3

#define SMELL_GONE_SPEED 50

#define SMELL_GONE_RATE 0.05

#define TRACE_REMEMBER 50

#define MAX_BLOCK 100

 

#define NULL 0

#define UP 1

#define DOWN 2

#define LEFT 3

#define RIGHT 4

#define SMELL_TYPE_FOOD 0

#define SMELL_TYPE_HOME 1

 

#include "stdio.h"

#include "conio.h"

#include "dos.h"

#include "stdlib.h"

#include "dos.h"

#include "process.h"

#include "ctype.h"

#include "math.h"

 

void WorldInitial(void);

void BlockInitial(void);

void CreatBlock(void);

void SaveBlock(void);

void LoadBlock(void);

void HomeFoodInitial(void);

void AntInitial(void);

void WorldChange(void);

void AntMove(void);

void AntOneStep(void);

void DealKey(char key);

void ClearSmellDisp(void);

void DispSmell(int type);

int AntNextDir(int xxx,int yyy,int ddir);

int GetMaxSmell(int type,int xxx,int yyy,int ddir);

int IsTrace(int xxx,int yyy);

int MaxLocation(int num1,int num2,int num3);

int CanGo(int xxx,int yyy,int ddir);

int JudgeCanGo(int xxx,int yyy);

int TurnLeft(int ddir);

int TurnRight(int ddir);

int TurnBack(int ddir);

 

int MainTimer(void);

char WaitForKey(int secnum);

void DispPlayTime(void);

int TimeUse(void);

void HideCur(void);

void ResetCur(void);

 

/* ---------------  */

struct HomeStruct

{

  int xxx,yyy;

  int amount;

  int TargetFood;

}home;

 

struct FoodStruct

{

  int xxx,yyy;

  int amount;

}food;

 

struct AntStruct

{

  int xxx,yyy;

  int dir;

  int speed;

  int SpeedTimer;

  int food;

  int SmellAmount[2];

  int tracex[TRACE_REMEMBER];

  int tracey[TRACE_REMEMBER];

  int TracePtr;

  int IQ;

}ant[MAX_ANT];

int AntNow;

int timer10ms;

struct time starttime,endtime;

int Smell[2][MAXX+1][MAXY+1];

int block[MAXX+1][MAXY+1];

int SmellGoneTimer;

int SmellDispFlag;

int CanFindFood;

int HardtoFindPath;

 

/* ----- Main -------- */

void main(void)

{

  char KeyPress;

  int tu;

 

  clrscr();

  HideCur();

  WorldInitial();

  do

  {

    timer10ms = MainTimer();

    if(timer10ms) AntMove();

    if(timer10ms) WorldChange();

    tu = TimeUse();

    if(tu>=60&&!CanFindFood)

    {

      gotoxy(1,MAXY+1);

      printf("Can not find food, maybe a block world.");

      WaitForKey(10);

      WorldInitial();

    }

    if(tu>=180&&home.amount<100&&!HardtoFindPath)

    {

      gotoxy(1,MAXY+1);

      printf("God! it is so difficult to find a path.");

      if(WaitForKey(10)==0x0d) WorldInitial();

      else

     {

        HardtoFindPath = 1;

        gotoxy(1,MAXY+1);

        printf("                     ");

     }

    }

    if(home.amount>=home.TargetFood)

    {

      gettime(&endtime);

      KeyPress = WaitForKey(60);

      DispPlayTime();

      WaitForKey(10);

      WorldInitial();

    }

    else if(kbhit())

    {

      KeyPress = getch();

      DealKey(KeyPress);

    }

    else KeyPress = NULL;

  }

  while(KeyPress!=ESC);

  gettime(&endtime);

  DispPlayTime();

  WaitForKey(10);

  clrscr();

  ResetCur();

}

 

/* ------ general sub process ----------- */

int MainTimer(void)

/* output: how much 10ms have pass from last time call this process */

{

  static int oldhund,oldsec;

  struct  time t;

  int timeuse;

 

  gettime(&t);

  timeuse = 0;

  if(t.ti_hund!=oldhund)

  {

    if(t.ti_sec!=oldsec)

    {

      timeuse+=100;

      oldsec = t.ti_sec;

    }

    timeuse+=t.ti_hund-oldhund;

    oldhund = t.ti_hund;

  }

  else timeuse = 0;

  return (timeuse);

}

 

char WaitForKey(int secnum)

/* funtion: if have key in, exit immediately, else wait 'secnum' senconds then exit

   input: secnum -- wait this senconds, must < 3600 (1 hour)

   output: key char, if no key in(exit when timeout), return NULL */

{

  int secin,secnow;

  int minin,minnow;

  int hourin,hournow;

  int secuse;

  struct  time t;

 

  gettime(&t);

  secin = t.ti_sec;

  minin = t.ti_min;

  hourin = t.ti_hour;

 

  do

  {

    if(kbhit()) return(getch());

    gettime(&t);

    secnow = t.ti_sec;

    minnow = t.ti_min;

    hournow = t.ti_hour;

 

    if(hournow!=hourin) minnow+=60;

    if(minnow>minin) secuse = (minnow-1-minin) + (secnow+60-secin);

    else secuse = secnow - secin;

 

    /* counting error check */

    if(secuse<0)

    {

      gotoxy(1,MAXY+1);

      printf("Time conuting error, any keyto exit...");

      getch();

      exit(3);

    }

  }

  while(secuse<=secnum);

  return (NULL);

}

 

void DispPlayTime(void)

{

  int ph,pm,ps;

 

  ph = endtime.ti_hour - starttime.ti_hour;

  pm = endtime.ti_min - starttime.ti_min;

  ps = endtime.ti_sec - starttime.ti_sec;

 

  if(ph<0) ph+=24;

  if(pm<0) { ph--; pm+=60; }

  if(ps<0) { pm--; ps+=60; }

 

  gotoxy(1,MAXY+1);

  printf("Time use: %d hour- %d min- %d sec ",ph,pm,ps);

}

 

int TimeUse(void)

{

  int ph,pm,ps;

 

  gettime(&endtime);

  ph = endtime.ti_hour - starttime.ti_hour;

  pm = endtime.ti_min - starttime.ti_min;

  ps = endtime.ti_sec - starttime.ti_sec;

 

  if(ph<0) ph+=24;

  if(pm<0) { ph--; pm+=60; }

  if(ps<0) { pm--; ps+=60; }

 

  return(ps+(60*(pm+60*ph)));

}

 

void HideCur(void)

{

  union REGS regs0;

  regs0.h.ah=1;

  regs0.h.ch=0x30;

  regs0.h.cl=0x31;

  int86(0x10,&regs0,&regs0);

}

 

void ResetCur(void)

{

  union REGS regs0;

  regs0.h.ah=1;

  regs0.h.ch=0x06;

  regs0.h.cl=0x07;

  int86(0x10,&regs0,&regs0);

}

 

/* ------------ main ANT programe ------------- */

void WorldInitial(void)

{

  int k,i,j;

  randomize();

  clrscr();

  HomeFoodInitial();

  for(AntNow=0;AntNow<MAX_ANT;AntNow++)

  {

    AntInitial();

  } /* of for AntNow */;

 

  BlockInitial();

  for(k=0;k<=1;k++)

  /* SMELL TYPE FOOD and HOME */

    for(i=0;i<=MAXX;i++)

      for(j=0;j<=MAXY;j++)

        Smell[k][i][j] = 0;

  SmellGoneTimer = 0;

  gettime(&starttime);

  SmellDispFlag = 0;

  CanFindFood = 0;

  HardtoFindPath = 0;

}

 

void BlockInitial(void)

{

  int i,j;

  int bn;

 

  for(i=0;i<=MAXX;i++)

    for(j=0;j<=MAXY;j++)

      block[i][j] = 0;

 

  bn = 1+ MAX_BLOCK/2 + random(MAX_BLOCK/2);

  for(i=0;i<=bn;i++) CreatBlock();

}

 

void CreatBlock(void)

{

  int x1,y1,x2,y2;

  int dx,dy;

  int i,j;

 

  x1 = random(MAXX)+1;

  y1 = random(MAXY)+1;

 

  dx = random(MAXX/10)+1;

  dy = random(MAXY/10)+1;

 

  x2 = x1+dx;

  y2 = y1+dy;

 

  if(x2>MAXX) x2 = MAXX;

  if(y2>MAXY) y2 = MAXY;

 

  if(food.xxx>=x1&&food.xxx<=x2&&food.yyy>=y1&&food.yyy<=y2) return;

  if(home.xxx>=x1&&home.xxx<=x2&&home.yyy>=y1&&home.yyy<=y2) return;

 

  for(i=x1;i<=x2;i++)

    for(j=y1;j<=y2;j++)

    {

      block[i][j] = 1;

      gotoxy(i,j);

      putch(BLOCK_CHAR);

    }

}

 

void SaveBlock(void)

{

 FILE *fp_block;

 char FileNameBlock[20];

 int i,j;

 

 gotoxy(1,MAXY+1);

  printf("                     ");

 gotoxy(1,MAXY+1);

 printf("Save to file...",FileNameBlock);

 gets(FileNameBlock);

 if(FileNameBlock[0]==0) strcpy(FileNameBlock,"Ant.ant");

 else strcat(FileNameBlock,".ant");

 

 if ((fp_block = fopen(FileNameBlock, "wb")) == NULL)

 { gotoxy(1,MAXY+1);

    printf("Creat file %s fail...",FileNameBlock);

  getch();

  exit(2);

 }

 gotoxy(1,MAXY+1);

  printf("                           ");

 

 fputc(home.xxx,fp_block);

 fputc(home.yyy,fp_block);

 fputc(food.xxx,fp_block);

 fputc(food.yyy,fp_block);

 

 for(i=0;i<=MAXX;i++)

    for(j=0;j<=MAXY;j++)

      fputc(block[i][j],fp_block);

 

  fclose(fp_block);

}

 

void LoadBlock(void)

{

 FILE *fp_block;

 char FileNameBlock[20];

 int i,j,k;

 

 gotoxy(1,MAXY+1);

  printf("                     ");

 gotoxy(1,MAXY+1);

 printf("Load file...",FileNameBlock);

 gets(FileNameBlock);

 if(FileNameBlock[0]==0) strcpy(FileNameBlock,"Ant.ant");

 else strcat(FileNameBlock,".ant");

 

 if ((fp_block = fopen(FileNameBlock, "rb")) == NULL)

 { gotoxy(1,MAXY+1);

    printf("Open file %s fail...",FileNameBlock);

  getch();

  exit(2);

 }

 

 clrscr();

 home.xxx = fgetc(fp_block);

 home.yyy = fgetc(fp_block);

 food.xxx = fgetc(fp_block);

 food.yyy = fgetc(fp_block);

 gotoxy(home.xxx,home.yyy); putch(HOME_CHAR);

  gotoxy(food.xxx,food.yyy); putch(FOOD_CHAR);

  food.amount = random(MAX_FOOD/3)+2*MAX_FOOD/3+1;

  /* food.amount = MAX_FOOD; */

  home.amount = 0;

  home.TargetFood =

    (food.amount<TARGET_FOOD)?food.amount:TARGET_FOOD;

 

 for(AntNow=0;AntNow<MAX_ANT;AntNow++)

  {

    AntInitial();

  } /* of for AntNow */;

 

 for(i=0;i<=MAXX;i++)

    for(j=0;j<=MAXY;j++)

    {

      block[i][j] = fgetc(fp_block);

      if(block[i][j])

      {

       gotoxy(i,j);

       putch(BLOCK_CHAR);

     }

    }

 

  for(k=0;k<=1;k++)

  /* SMELL TYPE FOOD and HOME */

    for(i=0;i<=MAXX;i++)

      for(j=0;j<=MAXY;j++)

        Smell[k][i][j] = 0;

  SmellGoneTimer = 0;

  gettime(&starttime);

  SmellDispFlag = 0;

  CanFindFood = 0;

  HardtoFindPath = 0;

 

  fclose(fp_block);

}

 

void HomeFoodInitial(void)

{

  int randnum;

  int homeplace;

  /* 1 -- home at left-up, food at right-down

     2 -- home at left-down, food at right-up

     3 -- home at right-up, food at left-down

     4 -- home at right-down, food at left-up */

 

  randnum = random(100);

  if(randnum<25) homeplace = 1;

  else if (randnum>=25&&randnum<50) homeplace = 2;

  else if (randnum>=50&&randnum<75) homeplace = 3;

  else homeplace = 4;

 

  switch(homeplace)

  {

    case 1: home.xxx = random(MAXX/3)+1;

        home.yyy = random(MAXY/3)+1;

        food.xxx = random(MAXX/3)+2*MAXX/3+1;

        food.yyy = random(MAXY/3)+2*MAXY/3+1;

        break;

    case 2: home.xxx = random(MAXX/3)+1;

        home.yyy = random(MAXY/3)+2*MAXY/3+1;

        food.xxx = random(MAXX/3)+2*MAXX/3+1;

        food.yyy = random(MAXY/3)+1;

        break;

    case 3: home.xxx = random(MAXX/3)+2*MAXX/3+1;

        home.yyy = random(MAXY/3)+1;

        food.xxx = random(MAXX/3)+1;

        food.yyy = random(MAXY/3)+2*MAXY/3+1;

        break;

    case 4: home.xxx = random(MAXX/3)+2*MAXX/3+1;

        home.yyy = random(MAXY/3)+2*MAXY/3+1;

        food.xxx = random(MAXX/3)+1;

        food.yyy = random(MAXY/3)+1;

        break;

  }

 

  food.amount = random(MAX_FOOD/3)+2*MAX_FOOD/3+1;

  /* food.amount = MAX_FOOD; */

  home.amount = 0;

  home.TargetFood = (food.amount<TARGET_FOOD)?food.amount:TARGET_FOOD;

 

  /* data correctness check */

  if(home.xxx<=0||home.xxx>MAXX||home.yyy<=0||home.yyy>MAXY||

     food.xxx<=0||food.xxx>MAXX||food.yyy<=0||food.yyy>MAXY||

     food.amount<=0)

  {

    gotoxy(1,MAXY+1);

    printf("World initial fail, any key to exit...");

    getch();

    exit(2);

  }

 

  gotoxy(home.xxx,home.yyy); putch(HOME_CHAR);

  gotoxy(food.xxx,food.yyy); putch(FOOD_CHAR);

}void AntInitial(void)

/* initial ant[AntNow] */

{

  int randnum;

  int i;

 

  ant[AntNow].xxx = home.xxx;

  ant[AntNow].yyy = home.yyy;

 

  randnum = random(100);

  if(randnum<25) ant[AntNow].dir = UP;

  else if (randnum>=25&&randnum<50) ant[AntNow].dir = DOWN;

  else if (randnum>=50&&randnum<75) ant[AntNow].dir = LEFT;

  else ant[AntNow].dir = RIGHT;

 

  ant[AntNow].speed = 2*(random(INI_SPEED/2)+1);

  ant[AntNow].SpeedTimer = 0;

  ant[AntNow].food = 0;

  ant[AntNow].SmellAmount[SMELL_TYPE_FOOD] = 0;

  ant[AntNow].SmellAmount[SMELL_TYPE_HOME] = MAX_SMELL;

  ant[AntNow].IQ = 1;

 

  for(i=0;i<TRACE_REMEMBER;i++)

  {

    ant[AntNow].tracex[i] = 0;

    ant[AntNow].tracey[i] = 0;

  }

  ant[AntNow].TracePtr = 0;

 

  /* a sepecail ant */

  if(AntNow==0) ant[AntNow].speed = INI_SPEED;

}

 

void WorldChange(void)

{

  int k,i,j;

  int smelldisp;

 

  SmellGoneTimer+=timer10ms;

  if(SmellGoneTimer>=SMELL_GONE_SPEED)

  {

    SmellGoneTimer = 0;

    for(k=0;k<=1;k++)

    /* SMELL TYPE FOOD and HOME */

      for(i=1;i<=MAXX;i++)

        for(j=1;j<=MAXY;j++)

        {

            if(Smell[k][i][j])

          {

              smelldisp = 1+((10*Smell[k][i][j])/(MAX_SMELL*SMELL_DROP_RATE));

              if(smelldisp>=30000||smelldisp<0) smelldisp = 30000;

              if(SmellDispFlag)

           {

                gotoxy(i,j);

                if((i==food.xxx&&j==food.yyy)||(i==home.xxx&&j==home.yyy))

                  /* don't over write Food and Home */;

              else

             {

                  if(smelldisp>9) putch('#');

                  else putch(smelldisp+'0');

             }

           }

              Smell[k][i][j]-= 1+(Smell[k][i][j]*SMELL_GONE_RATE);

              if(Smell[k][i][j]<0) Smell[k][i][j] = 0;

              if(SmellDispFlag)

           {

                if(Smell[k][i][j]<=2)

             {

                  gotoxy(i,j);

                  putch(SPACE);

             }

           }

          }

          } /* of one location */

  } /* of time to change the world */

} /* of world change */

 

void AntMove(void)

{

  int antx,anty;

  int smelltodrop,smellnow;

 

  for(AntNow=0;AntNow<MAX_ANT;AntNow++)

  {

    ant[AntNow].SpeedTimer+=timer10ms;

    if(ant[AntNow].SpeedTimer>=ant[AntNow].speed)

    {

      ant[AntNow].SpeedTimer = 0;

      gotoxy(ant[AntNow].xxx,ant[AntNow].yyy);

      putch(SPACE);

      AntOneStep();

      gotoxy(ant[AntNow].xxx,ant[AntNow].yyy);

      /* ant0 is a sepecail ant, use different color */

      if(AntNow==0) textcolor(0xd);

      if(ant[AntNow].food) putch(ANT_CHAR_FOOD);

      else putch(ANT_CHAR_EMPTY);

      if(AntNow==0) textcolor(0x7);

 

      /* remember trace */

      ant[AntNow].tracex[ant[AntNow].TracePtr] = ant[AntNow].xxx;

      ant[AntNow].tracey[ant[AntNow].TracePtr] = ant[AntNow].yyy;

      if(++(ant[AntNow].TracePtr)>=TRACE_REMEMBER) ant[AntNow].TracePtr = 0;

 

      /* drop smell */

      antx = ant[AntNow].xxx;

      anty = ant[AntNow].yyy;

 

      if(ant[AntNow].food)

      /* have food, looking for home */

     {

        if(ant[AntNow].SmellAmount[SMELL_TYPE_FOOD])

       {

          smellnow = Smell[SMELL_TYPE_FOOD][antx][anty];

          smelltodrop = ant[AntNow].SmellAmount[SMELL_TYPE_FOOD]*SMELL_DROP_RATE;

          if(smelltodrop>smellnow) Smell[SMELL_TYPE_FOOD][antx][anty] = smelltodrop;

          /* else Smell[...] = smellnow */

          ant[AntNow].SmellAmount[SMELL_TYPE_FOOD]-= smelltodrop;

          if(ant[AntNow].SmellAmount[SMELL_TYPE_FOOD]<0) ant[AntNow].SmellAmount[SMELL_TYPE_FOOD] = 0;

        } /* of have smell to drop */

      } /* of have food */

      else

      /* no food, looking for food */

     {

        if(ant[AntNow].SmellAmount[SMELL_TYPE_HOME])

       {

          smellnow = Smell[SMELL_TYPE_HOME][antx][anty];

          smelltodrop = ant[AntNow].SmellAmount[SMELL_TYPE_HOME]*SMELL_DROP_RATE;

          if(smelltodrop>smellnow) Smell[SMELL_TYPE_HOME][antx][anty] = smelltodrop;

          /* else Smell[...] = smellnow */

          ant[AntNow].SmellAmount[SMELL_TYPE_HOME]-= smelltodrop;

          if(ant[AntNow].SmellAmount[SMELL_TYPE_HOME]<0) ant[AntNow].SmellAmount[SMELL_TYPE_HOME] = 0;

        } /* of have smell to drop */

     }

    } /* of time to go */

    /* else not go */

  } /* of for AntNow */

 

  textcolor(FOOD_HOME_COLOR);

  gotoxy(home.xxx,home.yyy); putch(HOME_CHAR);

  gotoxy(food.xxx,food.yyy);

  if(food.amount>0) putch(FOOD_CHAR);

  else putch(FOOD_CHAR2);

  textcolor(7);

 

  gotoxy(1,MAXY+1);

  printf("Food %d, Home %d   ",food.amount,home.amount);

}

 

void AntOneStep(void)

{

  int ddir,tttx,ttty;

  int i;

 

  ddir = ant[AntNow].dir;

  tttx = ant[AntNow].xxx;

  ttty = ant[AntNow].yyy;

 

  ddir = AntNextDir(tttx,ttty,ddir);

 

  switch(ddir)

  {

    case UP:  ttty--;

          break;

    case DOWN:  ttty++;

          break;

    case LEFT:  tttx--;

          break;

    case RIGHT: tttx++;

          break;

    default:  break;

  } /* of switch dir */

 

  ant[AntNow].dir = ddir;

  ant[AntNow].xxx = tttx;

  ant[AntNow].yyy = ttty;

 

  if(ant[AntNow].food)

  /* this ant carry with food, search for home */

  {

    if(tttx==home.xxx&&ttty==home.yyy)

    {

      home.amount++;

      AntInitial();

    }

    if(tttx==food.xxx&&ttty==food.yyy)

      ant[AntNow].SmellAmount[SMELL_TYPE_FOOD] = MAX_SMELL;

  } /* of search for home */

  else

  /* this ant is empty, search for food */

  {

    if(tttx==food.xxx&&ttty==food.yyy)

    {

      if(food.amount>0)

     {

        ant[AntNow].food = 1;

        food.amount--;

        ant[AntNow].SmellAmount[SMELL_TYPE_FOOD] = MAX_SMELL;

        ant[AntNow].SmellAmount[SMELL_TYPE_HOME] = 0;

        ant[AntNow].dir = TurnBack(ant[AntNow].dir);

        for(i=0;i<TRACE_REMEMBER;i++)

       {

          ant[AntNow].tracex[i] = 0;

          ant[AntNow].tracey[i] = 0;

       }

        ant[AntNow].TracePtr = 0;

        CanFindFood = 1;

      } /* of still have food */

    }

    if(tttx==home.xxx&&ttty==home.yyy)

      ant[AntNow].SmellAmount[SMELL_TYPE_HOME] = MAX_SMELL;

  }  /* of search for food */

}

 

void DealKey(char key)

{

  int i;

  switch(key)

  {

    case 'p':   gettime(&endtime);

          DispPlayTime();

          getch();

          gotoxy(1,MAXY+1);

          for(i=1;i<=MAXX-1;i++) putch(SPACE);

          break;

    case 't':   if(SmellDispFlag)

        {

            SmellDispFlag=0;

            ClearSmellDisp();

        }

          else SmellDispFlag = 1;

          break;

    case '1':   DispSmell(SMELL_TYPE_FOOD);

          getch();

          ClearSmellDisp();

          break;

    case '2':   DispSmell(SMELL_TYPE_HOME);

          getch();

          ClearSmellDisp();

          break;

    case '3':   DispSmell(2);

          getch();

          ClearSmellDisp();

          break;

    case 's':   SaveBlock();

       break;

    case 'l':   LoadBlock();

       break;

    default:  gotoxy(1,MAXY+1);

          for(i=1;i<=MAXX-1;i++) putch(SPACE);

  } /* of switch */

}

 

void ClearSmellDisp(void)

{

  int k,i,j;

 

  for(k=0;k<=1;k++)

  /* SMELL TYPE FOOD and HOME */

    for(i=1;i<=MAXX;i++)

      for(j=1;j<=MAXY;j++)

       {

          if(Smell[k][i][j])

        {

            gotoxy(i,j);

            putch(SPACE);

        }

        } /* of one location */

}

 

void DispSmell(int type)

/* input: 0 -- Only display food smell

      1 -- Only display home smell

      2 -- Display both food and home smell

*/

{

  int k,i,j;

  int fromk,tok;

  int smelldisp;

 

  switch(type)

  {

    case 0: fromk = 0;

        tok = 0;

        break;

    case 1: fromk = 1;

        tok = 1;

        break;

    case 2: fromk = 0;

        tok = 1;

        break;

    default:fromk = 0;

        tok = 1;

        break;

  }

  SmellGoneTimer = 0;

  for(k=fromk;k<=tok;k++)

  /* SMELL TYPE FOOD and HOME */

    for(i=1;i<=MAXX;i++)

      for(j=1;j<=MAXY;j++)

       {

          if(Smell[k][i][j])

        {

            smelldisp = 1+((10*Smell[k][i][j])/(MAX_SMELL*SMELL_DROP_RATE));

            if(smelldisp>=30000||smelldisp<0) smelldisp = 30000;

            gotoxy(i,j);

            if(i!=food.xxx||j!=food.yyy)

          {

              if((i==food.xxx&&j==food.yyy)||(i==home.xxx&&j==home.yyy))

                /* don't over write Food and Home */;

            else

           {

                if(smelldisp>9) putch('#');

                else putch(smelldisp+'0');

           }

          }

        }

        } /* of one location */

}

 

int AntNextDir(int xxx,int yyy,int ddir)

{

  int randnum;

  int testdir;

  int CanGoState;

  int cangof,cangol,cangor;

  int msf,msl,msr,maxms;

  int type;

 

  CanGoState = CanGo(xxx,yyy,ddir);

  if(CanGoState==0||CanGoState==2||CanGoState==3||CanGoState==6) cangof = 1;

  else cangof = 0;

  if(CanGoState==0||CanGoState==1||CanGoState==3||CanGoState==5) cangol = 1;

  else cangol = 0;

  if(CanGoState==0||CanGoState==1||CanGoState==2||CanGoState==4) cangor = 1;

  else cangor = 0;

 

  if(ant[AntNow].food) type = SMELL_TYPE_HOME;

  else type = SMELL_TYPE_FOOD;

 

  msf = GetMaxSmell(type,xxx,yyy,ddir);

  msl = GetMaxSmell(type,xxx,yyy,TurnLeft(ddir));

  msr= GetMaxSmell(type,xxx,yyy,TurnRight(ddir));

  maxms = MaxLocation(msf,msl,msr);

  /* maxms - 1 - msf is MAX

         2 - msl is MAX

         3 - msr is MAX

         0 - all 3 number is 0 */

 

  testdir = NULL;

  switch(maxms)

  {

    case 0: /* all is 0, keep testdir = NULL, random select dir */

        break;

    case 1: if(cangof)

          testdir = ddir;

        else

          if(msl>msr) if(cangol) testdir = TurnLeft(ddir);

          else if(cangor) testdir = TurnRight(ddir);

        break;

    case 2: if(cangol)

          testdir = TurnLeft(ddir);

        else

          if(msf>msr) if(cangof) testdir = ddir;

          else if(cangor) testdir = TurnRight(ddir);

        break;

    case 3: if(cangor)

          testdir = TurnRight(ddir);

        else

          if(msf>msl) if(cangof) testdir =ddir;

          else if(cangol) testdir = TurnLeft(ddir);

        break;

    default:break;

  } /* of maxms */

 

  randnum = random(1000);

  if(randnum<SMELL_DROP_RATE*1000||testdir==NULL)

  /* 1. if testdir = NULL, means can not find the max smell or the dir to max smell can not go

     then random select dir

     2. if ant error, don't follow the smell, random select dir

  */

  {

    randnum = random(100);

    switch(CanGoState)

    {

      case 0: if(randnum<90) testdir = ddir;

          else if (randnum>=90&&randnum<95) testdir = TurnLeft(ddir);

          else testdir = TurnRight(ddir);

          break;

      case 1: if(randnum<50) testdir = TurnLeft(ddir);

          else testdir = TurnRight(ddir);

          break;

      case 2: if(randnum<90) testdir = ddir;

          else testdir = TurnRight(ddir);

          break;

      case 3: if(randnum<90) testdir = ddir;

          else testdir = TurnLeft(ddir);

          break;

      case 4: testdir = TurnRight(ddir);

          break;

      case 5: testdir = TurnLeft(ddir);

          break;

      case 6: testdir = ddir;

          break;

      case 7: testdir = TurnBack(ddir);

          break;

      default:testdir = TurnBack(ddir);

    } /* of can go state */

  }

  return(testdir);

}

int GetMaxSmell(int type,int xxx,int yyy,int ddir)

{

  int i,j;

  int ms; /* MAX smell */

 

  ms = 0;

  switch(ddir)

  {

    case UP:  for(i=xxx-ANT_EYESHOT;i<=xxx+ANT_EYESHOT;i++)

            for(j=yyy-ANT_EYESHOT;j<yyy;j++)

          {

              if(!JudgeCanGo(i,j)) continue;

              if((i==food.xxx&&j==food.yyy&&type==SMELL_TYPE_FOOD)||

                 (i==home.xxx&&j==home.yyy&&type==SMELL_TYPE_HOME))

           {

                ms = MAX_SMELL;

               break;

           }

              if(IsTrace(i,j)) continue;

              if(Smell[type][i][j]>ms) ms = Smell[type][i][j];

          }

          break;

    case DOWN:  for(i=xxx-ANT_EYESHOT;i<=xxx+ANT_EYESHOT;i++)

            for(j=yyy+1;j<=yyy+ANT_EYESHOT;j++)

          {

              if(!JudgeCanGo(i,j)) continue;

              if((i==food.xxx&&j==food.yyy&&type==SMELL_TYPE_FOOD)||

                 (i==home.xxx&&j==home.yyy&&type==SMELL_TYPE_HOME))

           {

                ms = MAX_SMELL;

               break;

           }

              if(IsTrace(i,j)) continue;

              if(Smell[type][i][j]>ms) ms = Smell[type][i][j];

          }

          break;

    case LEFT:  for(i=xxx-ANT_EYESHOT;i<xxx;i++)

            for(j=yyy-ANT_EYESHOT;j<=yyy+ANT_EYESHOT;j++)

          {

              if(!JudgeCanGo(i,j)) continue;

              if((i==food.xxx&&j==food.yyy&&type==SMELL_TYPE_FOOD)||

                 (i==home.xxx&&j==home.yyy&&type==SMELL_TYPE_HOME))

           {

                ms = MAX_SMELL;

               break;

           }

              if(IsTrace(i,j)) continue;

              if(Smell[type][i][j]>ms) ms = Smell[type][i][j];

          }

          break;

    case RIGHT: for(i=xxx+1;i<=xxx+ANT_EYESHOT;i++)

            for(j=yyy-ANT_EYESHOT;j<=yyy+ANT_EYESHOT;j++)

          {

              if(!JudgeCanGo(i,j)) continue;

              if((i==food.xxx&&j==food.yyy&&type==SMELL_TYPE_FOOD)||

                 (i==home.xxx&&j==home.yyy&&type==SMELL_TYPE_HOME))

           {

                ms = MAX_SMELL;

               break;

           }

              if(IsTrace(i,j)) continue;

              if(Smell[type][i][j]>ms) ms = Smell[type][i][j];

          }

          break;

    default:  break;

  }

  return(ms);

}

 

int IsTrace(int xxx,int yyy)

{

  int i;

 

  for(i=0;i<TRACE_REMEMBER;i++)

    if(ant[AntNow].tracex[i]==xxx&&ant[AntNow].tracey[i]==yyy) return(1);

  return(0);

}

 

int MaxLocation(int num1,int num2,int num3)

{

  int maxnum;

 

  if(num1==0&&num2==0&&num3==0) return(0);

 

  maxnum = num1;

  if(num2>maxnum) maxnum = num2;

  if(num3>maxnum) maxnum = num3;

 

  if(maxnum==num1) return(1);

  if(maxnum==num2) return(2);

  if(maxnum==num3) return(3);

}

 

int CanGo(int xxx,int yyy,int ddir)

/* input: xxx,yyy - location of ant

      ddir - now dir

   output: 0 - forward and left and right can go

       1 - forward can not go

       2 - left can not go

       3 - right can not go

       4 - forward and left can not go

       5 - forward and right can not go

       6 - left and right can not go

       7 - forward and left and right all can not go

*/

{

  int tx,ty,tdir;

  int okf,okl,okr;

 

  /* forward can go ? */

  tdir = ddir;

  tx = xxx;

  ty = yyy;

  switch(tdir)

  {

    case UP:  ty--;

          break;

    case DOWN:  ty++;

          break;

    case LEFT:  tx--;

          break;

    case RIGHT: tx++;

          break;

    default:  break;

  } /* of switch dir */

  if(JudgeCanGo(tx,ty)) okf = 1;

  else okf = 0;

 

  /* turn left can go ? */

  tdir = TurnLeft(ddir);

  tx = xxx;

  ty = yyy;

  switch(tdir)

  {

    case UP:  ty--;

          break;

    case DOWN:  ty++;

          break;

    case LEFT:  tx--;

          break;

    case RIGHT: tx++;

          break;

    default:  break;

  } /* of switch dir */

  if(JudgeCanGo(tx,ty)) okl = 1;

  else okl = 0;

 

  /* turn right can go ? */

  tdir = TurnRight(ddir);

  tx = xxx;

  ty = yyy;

  switch(tdir)

  {

    case UP:  ty--;

          break;

    case DOWN:  ty++;

          break;

    case LEFT:  tx--;

          break;

    case RIGHT: tx++;

          break;

    default:  break;

  } /* of switch dir */

  if(JudgeCanGo(tx,ty)) okr = 1;

  else okr = 0;

 

  if(okf&&okl&&okr) return(0);

  if(!okf&&okl&&okr) return(1);

  if(okf&&!okl&&okr) return(2);

  if(okf&&okl&&!okr) return(3);

  if(!okf&&!okl&&okr) return(4);

  if(!okf&&okl&&!okr) return(5);

  if(okf&&!okl&&!okr) return(6);

  if(!okf&&!okl&&!okr) return(7);

  return(7);

}

 

int JudgeCanGo(int xxx,int yyy)

/* input: location to judeg

   output: 0 -- can not go

       1 -- can go

*/

{

  int i,j;

 

  if(xxx<=0||xxx>MAXX) return(0);

  if(yyy<=0||yyy>MAXY) return(0);

  if(block[xxx][yyy]) return(0);

  return(1);

}

 

int TurnLeft(int ddir)

{

  switch(ddir)

  {

    case UP:  return(LEFT);

    case DOWN:  return(RIGHT);

    case LEFT:  return(DOWN);

    case RIGHT: return(UP);

    default:  break;

  } /* of switch dir */

}

 

int TurnRight(int ddir)

{

  switch(ddir)

  {

    case UP:  return(RIGHT);

    case DOWN:  return(LEFT);

    case LEFT:  return(UP);

    case RIGHT: return(DOWN);

    default:  break;

  } /* of switch dir */

}

 

int TurnBack(int ddir)

{

  switch(ddir)

  {

    case UP:  return(DOWN);

    case DOWN:  return(UP);

    case LEFT:  return(RIGHT);

    case RIGHT: return(LEFT);

    default:  break;

  } /* of switch dir */

}

 

算法三:

四种常用排序方法的基本思想和PHP实现源代码

By Minidxer | January 31, 2008

 

 

 插入排序(Insertion Sort),选择排序(Selection Sort),冒泡排序和快速排序是我们经常会用到的排序算法。下面是这几种算法的基本思想和相对应的PHP实现代码。

 

 

 

●插入排序(Insertion Sort)的基本思想是:每次将一个待排序的记录,按其关键字大小插入到前面已经排好序的子文件中的适当位置,直到全部记录插入完成为止。

 

//插入排序(一维数组)

function insert_sort($arr){

    $count = count($arr);

    for($i=1; $i<$count; $i++){

        $tmp = $arr[$i];

        $j = $i - 1;

        while($arr[$j] > $tmp){

            $arr[$j+1] = $arr[$j];

            $arr[$j] = $tmp;

            $j--;

         }

     }

    return $arr;

}●选择排序(Selection Sort)的基本思想是:每一趟从待排序的记录中选出关键字最小的记录,顺序放在已排好序的子文件的最后,直到全部记录排序完毕。

 

//选择排序(一维数组)

function select_sort($arr){

    $count = count($arr);

    for($i=0; $i<$count; $i++){

        $k = $i;

        for($j=$i+1; $j<$count; $j++){

            if ($arr[$k] > $arr[$j])

                $k = $j;

            if ($k != $i){

                $tmp = $arr[$i];

                $arr[$i] = $arr[$k];

                $arr[$k] = $tmp;

             }

         }

     }

    return $arr;

}●冒泡排序的基本思想是:两两比较待排序记录的关键字,发现两个记录的次序相反时即进行交换,直到没有反序的记录为止。

 

//冒泡排序(一维数组)

function bubble_sort($array){

    $count = count($array);

    if ($count <= 0) return false;

    for($i=0; $i<$count; $i++){

        for($j=$count-1; $j>$i; $j--){

            if ($array[$j] < $array[$j-1]){

                $tmp = $array[$j];

                $array[$j] = $array[$j-1];

                $array[$j-1] = $tmp;

             }

         }

     }

    return $array;

} ●快速排序实质上和冒泡排序一样,都是属于交换排序的一种应用。所以基本思想和上面的冒泡排序是一样的。

 

//快速排序(一维数组)

function quick_sort($array){

  if (count($array) <= 1) return $array;

 

  $key = $array[0];

  $left_arr = array();

  $right_arr = array();

  for ($i=1; $i<count($array); $i++){

    if ($array[$i] <= $key)

      $left_arr[] = $array[$i];

    else

      $right_arr[] = $array[$i];

  }

  $left_arr = quick_sort($left_arr);

  $right_arr = quick_sort($right_arr);

 

  return array_merge($left_arr, array($key), $right_arr);

}

 

算法四:

汉诺塔算法的递归与非递归的C以及C++源代码

By Minidxer | January 30, 2008

 

 

 汉诺塔(又称河内塔)问题其实是印度的一个古老的传说。

 

开天辟地的神勃拉玛(和中国的盘古差不多的神吧)在一个庙里留下了三根金刚石的棒,第一根上面套着64个圆的金片,最大的一个在底下,其余一个比一个小,依次叠上去,庙里的众僧不倦地把它们一个个地从这根棒搬到另一根棒上,规定可利用中间的一根棒作为帮助,但每次只能搬一个,而且大的不能放在小的上面。计算结果非常恐怖(移动圆片的次数)18446744073709551615,众僧们即便是耗尽毕生精力也不可能完成金片的移动了。

 

 

 

 

 

算法介绍:

其实算法非常简单,当盘子的个数为n时,移动的次数应等于2^n - 1(有兴趣的可以自己证明试试看)。后来一位美国学者发现一种出人意料的简单方法,只要轮流进行两步操作就可以了。首先把三根柱子按顺序排成品字型,把所有的圆盘按从大到小的顺序放在柱子A上,根据圆盘的数量确定柱子的排放顺序:若n为偶数,按顺时针方向依次摆放 A B C

n为奇数,按顺时针方向依次摆放 A C B

1)按顺时针方向把圆盘1从现在的柱子移动到下一根柱子,即当n为偶数时,若圆盘1在柱子A,则把它移动到B;若圆盘1在柱子B,则把它移动到C;若圆盘1在柱子C,则把它移动到A

2)接着,把另外两根柱子上可以移动的圆盘移动到新的柱子上。即把非空柱子上的圆盘移动到空柱子上,当两根柱子都非空时,移动较小的圆盘。这一步没有明确规定移动哪个圆盘,你可能以为会有多种可能性,其实不然,可实施的行动是唯一的。

3)反复进行(1)(2)操作,最后就能按规定完成汉诺塔的移动。

 

所以结果非常简单,就是按照移动规则向一个方向移动金片:

3阶汉诺塔的移动:AC,AB,CB,AC,BA,BC,AC

 

汉诺塔问题也是程序设计中的经典递归问题,下面我们将给出递归和非递归的不同实现源代码。

 

●汉诺塔算法的递归实现C++源代码

 

#include <fstream>

#include <iostream>

using namespace std;

ofstream fout("out.txt");

void Move(int n,char x,char y)

{

  fout<<""<<n<<"号从"<<x<<"挪动到"<<y<<endl;

}

void Hannoi(int n,char a,char b,char c)

{

      if(n==1)

              Move(1,a,c);

    else

    {

          Hannoi(n-1,a,c,b);

            Move(n,a,c);

            Hannoi(n-1,b,a,c);

    }

}

int main()

{

    fout<<"以下是7层汉诺塔的解法:"<<endl;

    Hannoi(7,'a','b','c');

    fout.close();

    cout<<"输出完毕!"<<endl;

    return 0;

}●汉诺塔算法的递归实现C源代码:

 

#include<stdio.h>

void hanoi(int n,char A,char B,char C)

{

if(n==1)

{

  printf("Move disk %d from %c to %c\n",n,A,C);

}

else

{

  hanoi(n-1,A,C,B);

  printf("Move disk %d from %c to %c\n",n,A,C);

  hanoi(n-1,B,A,C);

}

}

main()

{

int n;

printf("请输入数字n以解决n阶汉诺塔问题:\n");

scanf("%d",&n);

hanoi(n,'A','B','C');

}

 

●汉诺塔算法的非递归实现C++源代码

 

#include <iostream>

using namespace std;

 

//圆盘的个数最多为64

const int MAX = 64;

 

//用来表示每根柱子的信息

struct st{

      int s[MAX]; //柱子上的圆盘存储情况

      int top; //栈顶,用来最上面的圆盘

      char name; //柱子的名字,可以是ABC中的一个

      int Top()//取栈顶元素

      {

            return s[top];

      }

      int Pop()//出栈

      {

            return s[top--];

      }

      void Push(int x)//入栈

      {

            s[++top] = x;

      }

} ;

 

long Pow(int x, int y); //计算x^y

void Creat(st ta[], int n); //给结构数组设置初值

void Hannuota(st ta[], long max); //移动汉诺塔的主要函数

 

int main(void)

{

      int n;

      cin >> n; //输入圆盘的个数

      st ta[3]; //三根柱子的信息用结构数组存储

      Creat(ta, n); //给结构数组设置初值

 

      long max = Pow(2, n) - 1;//动的次数应等于2^n - 1

      Hannuota(ta, max);//移动汉诺塔的主要函数

 

      system("pause");

      return 0;

}

 

void Creat(st ta[], int n)

{

      ta[0].name = 'A';

      ta[0].top = n-1;

     //把所有的圆盘按从大到小的顺序放在柱子A

      for (int i=0; i<n; i++)

            ta[0].s[i] = n - i;

      //柱子BC上开始没有没有圆盘

      ta[1].top = ta[2].top = 0;

      for (int i=0; i<n; i++)

            ta[1].s[i] = ta[2].s[i] = 0;

     //n为偶数,按顺时针方向依次摆放 A B C

      if (n%2 == 0)

      {

            ta[1].name = 'B';

            ta[2].name = 'C';

      }

      else  //n为奇数,按顺时针方向依次摆放 A C B

      {

            ta[1].name = 'C';

            ta[2].name = 'B';

      }

}

 

long Pow(int x, int y)

{

      long sum = 1;

      for (int i=0; i<y; i++)

            sum *= x;

 

      return sum;

}

 

void Hannuota(st ta[], long max)

{

  int k = 0; //累计移动的次数

  int i = 0;

  int ch;

  while (k < max)

  {

    //按顺时针方向把圆盘1从现在的柱子移动到下一根柱子

    ch = ta[i%3].Pop();

   ta[(i+1)%3].Push(ch);

   cout << ++k << ": " <<

         "Move disk " << ch << " from " << ta[i%3].name <<

         " to " << ta[(i+1)%3].name << endl;

   i++;

   //把另外两根柱子上可以移动的圆盘移动到新的柱子上

   if (k < max)

   {         //把非空柱子上的圆盘移动到空柱子上,当两根柱子都为空时,移动较小的圆盘

    if (ta[(i+1)%3].Top() == 0 ||

        ta[(i-1)%3].Top() > 0 &&

        ta[(i+1)%3].Top() > ta[(i-1)%3].Top())

   {

        ch =  ta[(i-1)%3].Pop();

        ta[(i+1)%3].Push(ch);

        cout << ++k << ": " << "Move disk "

             << ch << " from " << ta[(i-1)%3].name

             << " to " << ta[(i+1)%3].name << endl;

    }

    else

    {

       ch =  ta[(i+1)%3].Pop();

       ta[(i-1)%3].Push(ch);

       cout << ++k << ": " << "Move disk "

            << ch << " from " << ta[(i+1)%3].name

            << " to " << ta[(i-1)%3].name << endl;

    }

 }

}

}

 

算法五:

DES加密标准的说明以及加密/解密函数的实现源代码

By Minidxer | January 29, 2008

 

 

下面是来自维基的关于DES的说明: 数据加密标准( DES )是一种加密演算法(一种加密信息的方法), 1976年被美国联邦政府的联邦信息处理标准(FIPS)所选中,随后既在国际上广泛流传开来。这个演算法因为包含一些机密设计元素,相关的短密钥长度以及被怀疑内含国家安全局(NSA)的后门而在开始是有争议的,DES因此收到强烈的学院派式的审查,并以此推动了现代的分组密码及其密码分析。这个演算法因为包含一些机密设计元素,相关的短密钥长度以及被怀疑内含国家安全局(NSA)的后门而在开始是有争议的,DES因此收到强烈的学院派式的审查,并以此推动了现代的分组密码及其密码分析。

 

 

 

DES现在已经不被视为一种安全的加密演算法,因为它使用的56位秘钥过短,以现代计算能力,24小时内极可能被破解。 也有一些分析报告提出了该演算法的理论上的弱点,虽然实际情况未必出现。该标准在最近已经被高级加密标准(AES)所取代。

 

虽然是一种被取代了的算法,不过通过理解和研究这种算法的实现,还是可以带给我们不少启示的。下面是实现的C#代码:

 

using System;

using System.Drawing;

using System.Collections;

using System.ComponentModel;

using System.Windows.Forms;

using System.Data;

using System.Text;

using System.IO;

using System.Security.Cryptography;

 

private void menuItem13_Click(

    object sender,

    System.EventArgs e)

{

    //对应加密函数DSACrypData(string  strcrypto)

    string strcrypto=richTextBox1.Text;

    DSACrypData(strcrypto);

}

 

public static void DSACrypData(string  strcrypto)

{

    //先要将字符串转换为字节数组,这与编码有关。

    string str = "this is a test.";

    byte[] bytes = Encoding.ASCII.GetBytes(str);

    //选择签名方式,有RSADSA

    DSACryptoServiceProvider dsac =

             new DSACryptoServiceProvider();

    byte[] sign = dsac.SignData(bytes);

    //sign便是出来的签名结果。

 

    //下面是认证了

    DSACryptoServiceProvider dsac2 =

          new DSACryptoServiceProvider();

    dsac2.FromXmlString(dsac.ToXmlString(false));

    bool ver = dsac2.VerifyData(bytes, sign);

    if (ver)

    {

        MessageBox.Show("通过");

    }

    else

    {

        MessageBox.Show("不能通过");

    }

}

 

private void menuItem17_Click(

    object sender,

     System.EventArgs e)

{

    //对应加密函数DSACrypData(string  strcrypto)

    string strData=richTextBox1.Text;

    richTextBox2.Text=DESEncodeData(strData);

}

public static string DESEncodeData(string data)

{

    string KEY_64 = "VavicApp";

    string IV_64 = "VavicApp";

    byte[] byKey =

         System.Text.ASCIIEncoding.ASCII.GetBytes(KEY_64);

    byte[] byIV =

         System.Text.ASCIIEncoding.ASCII.GetBytes(IV_64);

 

    DESCryptoServiceProvider cryptoProvider =

                            new DESCryptoServiceProvider();

    int i = cryptoProvider.KeySize;

    MemoryStream ms = new MemoryStream();

    CryptoStream cst =

        new CryptoStream(ms,

        cryptoProvider.CreateEncryptor(byKey,byIV),

        CryptoStreamMode.Write);

 

    StreamWriter sw = new StreamWriter(cst);

    sw.Write(data);

    sw.Flush();

    cst.FlushFinalBlock();

    sw.Flush();

    return Convert.ToBase64String(

        ms.GetBuffer(),0,(int)ms.Length);

}

 

private void menuItem21_Click(

    object sender,

     System.EventArgs e)

{

    //对应加密函数DSACrypData(string  strcrypto)

    string strData=richTextBox1.Text;

    richTextBox2.Text=DESDecodeData(strData);

}

 

public static string DESDecodeData(string data)

{

    string KEY_64 = "VavicApp";

    string IV_64 = "VavicApp";

    byte[] byKey =

        System.Text.ASCIIEncoding.ASCII.GetBytes(KEY_64);

    byte[] byIV =

        System.Text.ASCIIEncoding.ASCII.GetBytes(IV_64);

 

    byte[] byEnc;

    try

    {

        byEnc = Convert.FromBase64String(data);

    }

    catch

    {

        return null;

    }

 

    DESCryptoServiceProvider cryptoProvider =

        new DESCryptoServiceProvider();

    MemoryStream ms = new MemoryStream(byEnc);

    CryptoStream cst =

        new CryptoStream(ms,

        cryptoProvider.CreateDecryptor(byKey,byIV),

        CryptoStreamMode.Read);

    StreamReader sr = new StreamReader(cst);

    return sr.ReadToEnd();

}

 

算法六:

Stein算法的简单描述以及C++/Java的三种实现源代码

By Minidxer | January 29, 2008

 

 

 在欧几里德算法的简单描述以及C++Java的各自实现代码中介绍的欧几里德算法是计算两个数最大公约数的传统算法,无论从理论还是从实际效率上都是很好的。但是却有一个致命的缺陷,这个缺陷在素数比较小的时候一般是感觉不到的,只有在大素数时才会显现出来。

一般实际应用中的整数很少会超过64位(当然现在已经允许128位了),对于这样的整数,计算两个数之间的模是很简单的。对于字长为32位的平台,计算两个不超过32位的整数的模,只需要一个指令周期,而计算64位以下的整数模,也不过几个周期而已。但是对于更大的素数,这样的计算过程就不得不由用户来设计,为了计算两个超过 64位的整数的模,用户也许不得不采用类似于多位数除法手算过程中的试商法,这个过程不但复杂,而且消耗了很多CPU时间。对于现代密码算法,要求计算 128位以上的素数的情况比比皆是,设计这样的程序迫切希望能够抛弃除法和取模。

 

 

 

J. Stein 1961年提出的Stein算法很好的解决了欧几里德算法中的这个缺陷,Stein算法只有整数的移位和加减法,为了说明Stein算法的正确性,首先必须注意到以下结论:

gcd(a,a) = a,也就是一个数和他自身的公约数是其自身

gcd(ka,kb) = k gcd(a,b),也就是最大公约数运算和倍乘运算可以交换,特殊的,当k=2时,说明两个偶数的最大公约数必然能被2整除。

 

根据上面的规律,Stein算法如下:

如果A=0B是最大公约数,算法结束

如果B=0A是最大公约数,算法结束

设置A1 = AB1=BC1 = 1

如果AnBn都是偶数,则An+1 =An /2Bn+1 =Bn /2Cn+1 =Cn *2(注意,乘2只要把整数左移一位即可,除2只要把整数右移一位即可)

如果An是偶数,Bn不是偶数,则An+1 =An /2Bn+1 =Bn Cn+1 =Cn (很显然啦,2不是奇数的约数)

如果Bn是偶数,An不是偶数,则Bn+1 =Bn /2An+1 =An Cn+1 =Cn (很显然啦,2不是奇数的约数)

如果AnBn都不是偶数,则An+1 =|An -Bn|Bn+1 =min(An,Bn)Cn+1 =Cn n++,转4

 

看到这里,我们已经可以给出Stein算法和欧几里德方法效率上的差别了:

在欧几里德算法的简单描述以及C++Java的各自实现代码中可以知道,欧几里德算法最恶劣的情况是,每次迭代a = 2b -1,这样,迭代后,r= b-1。如果a小于2N,这样大约需要 4N次迭代。而Stein算法,每次迭代后,显然AN+1BN+1 ANBN/2,最大迭代次数也不超过4N次。也就是说,迭代次数几乎是相等的。但是,需要注意的是,对于大素数,试商法将使每次迭代都更复杂,因此对于大素数Stein将更有优势。

 

●下面是C++/java 实现(由于是函数体,语法一样)

 

// c++/java stein 算法

int gcd(int a,int b){

    if(a<b)

    {

        //arrange so that a>b

        int temp = a;

        a = b;

        b=temp;

    }

 

    if(0==b)//the base case

        return a;

 

    if(a%2==0 && b%2 ==0)//a and b are even

        return 2*gcd(a/2,b/2);

 

    if ( a%2 == 0)// only a is even

        return gcd(a/2,b);

 

    if ( b%2==0 )// only b is even

        return gcd(a,b/2);

 

        return gcd((a+b)/2,(a-b)/2);// a and b are odd

 

}

●下面是C++的另一种实现:

 

#include <iostream>

#include <math.h>

using namespace std;

unsigned int gcd(unsigned int a,unsigned int b)

{

if(a == 0)

return b;

if(b == 0)

return a;

int p = 0;

label: while((!(a % 2)) && (!(b % 2)))

{

a /= 2;

b /= 2;

p ++;

}

while(!(a % 2))

{

a /= 2;

}

while(!(b % 2))

{

b /= 2;

}

if((b % 2) && (a % 2))

{

unsigned int temp;

temp = a;

a = b;

b = temp > b ? temp - b:b - temp;

}

if(b != 0)

goto label;

return a * pow(2,p);

}

int main(){

unsigned int i = gcd(456789988888,77888888888);

cout<<i;

system("pause");

}

int g_cd2(int a,int b)

{

  int c=1;

  int m=a,n=b;

  while(m!=0&&n!=0)

  {

    if (m%2==0&&n%2==0)

    {

      m /= 2;

      n /= 2;

      c *= 2;

      continue;

    }

    if (m%2==0&&n%2!=0)

    {

      m /= 2;

      continue;

    }

    if (m%2!=0&&n%2==0)

    {

      n /= 2;

      continue;

    }

    if (m%2!=0&&n%2!=0)

    {

      int i=m;

      m= m>n ? m-n:n-m;   //m=abs(m-n);

      if(i<n)

          n=i;

      continue;

    }

  }

  if (m==0)

    return n*c;

  if (n==0)

    return m*c;

}

●下面是微软的一个sdk里的代码,我们也可以参考一下

 

int GCD(int a, int b)

{

    int gcd;

    if (a < b)

    {

        gcd = GCD(b, a);

    }

    else

    {

        assert(a > 0);

        assert(b >= 0);

        while (b != 0)

        {

            int t = a % b;

            a = b;

            b = t;

        }

        gcd = a;

    }

    return gcd;

}

 

算法七:

欧几里德算法的简单描述以及C++Java的各自实现(源代码)

By Minidxer | January 29, 2008

 

 

 欧几里德算法描述:

欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数。其计算原理依赖于下面的定理:

定理:gcd(a,b) = gcd(b,a mod b)

证明:a可以表示成a = kb + r,则r = a mod b

假设da,b的一个公约数,则有d|a, d|b,而r = a - kb,因此d|r ,因此d(b,a mod b)的公约数

假设d (b,a mod b)的公约数,则d | b , d |r ,但是a = kb +r ,因此d也是(a,b)的公约数

因此(a,b)(b,a mod b)的公约数是一样的,其最大公约数也必然相等,得证

 

 

 

下面是该算法的C++实现:

 

void swap(int & a, int & b){

    int c = a;

    a = b;

    b = c;

}

 

int gcd(int a,int b){

    if(0 == a ){

        return b;

    }

 

    if( 0 == b){

        return a;

    }

 

    if(a > b){

        swap(a,b);

    }

 

    int c;

    for(c = a % b ; c > 0 ; c = a % b){

        a = b;

        b = c;

    }

 

    return b;

}下面是Java实现代码:

 

package algorithm;

/**

 *<p>hibernate-tutorialDescription:欧几里德算法</p>

 *@version1.0.0

 *@CopyrightCopyright(c)2008

 */

publicclass MaxFeed{

    publicint getnum(int m,int n){

        int r=getleave(m,n);

        while(r!=0){

            int[] s=swapnum(m,n,r);

            m=s[0];

            n=s[1];

            r=getleave(m,n);

        }

        return n;

    }

    /**

     *@paramm

     *@paramn

     *@return

     */

    privateint getleave(int m,int n){

        int r=m%n;

        return r;

    }

    /**

     *<p>comments:交换

     *          </p>

     *@paramm

     *@paramn

     *@paramr

     *@return

     */

    privateint[] swapnum(int m,int n,int r){

        m=n;

        n=r;

        int[] s=newint[2];

        s[0]=m;

        s[1]=n;

        return s;

    }

    /**

     *<p>comments:测试用例

     *          </p>

     *@paramargs

     */

    publicstaticvoid main(String[] args){

        MaxFeed maxFeed=new MaxFeed();

        int r=maxFeed.getnum(96,27);

        System.out.println("***********************************\n\n\n");

        System.out.println("                 "+r);

        System.out.println("***********************************");

    }

}

 

算法八:

约瑟夫环问题(Josephus)的两种解法(源代码)

By Minidxer | January 28, 2008

 

 

 算法描述: 有编号从1NN个人坐成一圈报数,报到M的人出局,下一位再从1开始, 如此持续,直止剩下一位为止,报告此人的编号X。输入N,M,求出X。下面给出两种解法,前面的是比较常规的解法,比较适合“名门正派”,而后面一种则非常巧妙……

 

 

 

注意点:由于当某个人退出圆圈后,报数的工作要从下一个人开始继续,剩下的人仍然是围成一个圆圈的,可以使用循环表,由于退出圆圈的工作对应着表中结点的删除操作,对于这种删除操作频繁的情况,选用效率较高的链表结构,为了程序指针每一次都指向一个具体的代表一个人的结点而不需要判断,链表不带头结点。所以,对于所有人围成的圆圈所对应的数据结构采用一个不带头结点的循环链表来描述。设头指针为p,并根据具体情况移动。为了记录退出的人的先后顺序,采用一个顺序表进行存储。程序结束后再输出依次退出的人的编号顺序。由于只记录各个结点的number值就可以,所以定义一个整型一维数组。如:int  quit[n];n为一个根据实际问题定义的一个足够大的整数。

 

●一般解法:

 

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <malloc.h>

 

/* 结构体和函数声明 */

typedef struct _node_t

{

    int             n_num;

    struct _node_t *next;

} node_t;

 

node_t         *node_t_create(int n);

node_t         *node_t_get(node_t **pn, int m);

 

/* 功能函数实现 */

 

/*

 *  name: node_t_create

 *  params:

 *    n         [in]        输入要构造的链表的个数

 *  return:

 *    返回构造成功的环形单向链表指针

 *  notes:

 *    构造节点数量为 n 的环形单向链表

 *

 */

node_t * node_t_create(int n)

{

    node_t *p_ret   = NULL;

 

    if (0 != n)

    {

        int     n_idx   = 1;

        node_t *p_node  = NULL;

 

        /* 构造 n node_t */

        p_node = (node_t *) malloc(n * sizeof(node_t));

        if (NULL == p_node)

            return NULL;

        else

            memset(p_node, 0, n * sizeof(node_t));

 

        /* 内存空间申请成功 */

        p_ret = p_node;

        for (; n_idx < n; n_idx++)

        {

            p_node->n_num = n_idx;

            p_node->next = p_node + 1;

            p_node = p_node->next;

        }

        p_node->n_num = n;

        p_node->next = p_ret;

    }

 

    return p_ret;

}

 

/*

 *  name: main

 *  params:

 *    none

 *  return:

 *    int

 *  notes:

 *    main function

 */

int main()

{

    int     n, m;

    node_t *p_list, *p_iter;

 

    n = 20; m = 6;

 

    /* 构造环形单向链表 */

    p_list = node_t_create(n);

 

    /* Josephus 循环取数 */

    p_iter = p_list;

    m %= n;

    while (p_iter != p_iter->next)

    {

        int i   = 1;

 

        /* 取到第 m-1 个节点 */

        for (; i < m - 1; i++)

        {

            p_iter = p_iter->next;

        }

 

        /* 输出第 m 个节点的值 */

        printf("%d\n", p_iter->next->n_num);

 

        /* 从链表中删除第 m 个节点 */

        p_iter->next = p_iter->next->next;

        p_iter = p_iter->next;

    }

    printf("%d\n", p_iter->n_num);

 

    /* 释放申请的空间 */

    free(p_list);

}●另一种比较巧妙的解法int f(int n, int m)

{

    int i, r = 0;

    for (i = 2; i <= n; i++)

        r = (r + m) % i;

    return r+1;

}

 

算法九:

几种经典的Hash算法的实现(源代码)

By Minidxer | January 27, 2008

 

 

 哈希算法将任意长度的二进制值映射为固定长度的较小二进制值,这个小的二进制值称为哈希值。哈希值是一段数据唯一且极其紧凑的数值表示形式。如果散列一段明文而且哪怕只更改该段落的一个字母,随后的哈希都将产生不同的值。要找到散列为同一个值的两个不同的输入,在计算上是不可能的,所以数据的哈希值可以检验数据的完整性。

 

 

 

链表查找的时间效率为O(N),二分法为log2NB+ Treelog2N,但Hash链表查找的时间效率为O(1)

 

设计高效算法往往需要使用Hash链表,常数级的查找速度是任何别的算法无法比拟的,Hash链表的构造和冲突的不同实现方法对效率当然有一定的影响,然 Hash函数是Hash链表最核心的部分,下面是几款经典软件中使用到的字符串Hash函数实现,通过阅读这些代码,我们可以在Hash算法的执行效率、离散性、空间利用率等方面有比较深刻的了解。

 

下面分别介绍几个经典软件中出现的字符串Hash函数。

 

PHP中出现的字符串Hash函数

 

static unsigned long hashpjw(char *arKey, unsigned int nKeyLength)

{

unsigned long h = 0, g;

char *arEnd=arKey+nKeyLength;

 

while (arKey < arEnd) {

h = (h << 4) + *arKey++;

if ((g = (h & 0xF0000000))) {

h = h ^ (g >> 24);

h = h ^ g;

}

}

return h;

}OpenSSL中出现的字符串Hash函数

 

unsigned long lh_strhash(char *str)

{

int i,l;

unsigned long ret=0;

unsigned short *s;

 

if (str == NULL) return(0);

l=(strlen(str)+1)/2;

s=(unsigned short *)str;

 

for (i=0; i

ret^=(s[i]<<(i&0x0f));

return(ret);

}

 

/* The following hash seems to work very well on normal text strings

* no collisions on /usr/dict/words and it distributes on %2^n quite

* well, not as good as MD5, but still good.

*/

unsigned long lh_strhash(const char *c)

{

unsigned long ret=0;

long n;

unsigned long v;

int r;

 

if ((c == NULL) || (*c == '\0'))

return(ret);

/*

unsigned char b[16];

MD5(c,strlen(c),b);

return(b[0]|(b[1]<<8)|(b[2]<<16)|(b[3]<<24));

*/

 

n=0x100;

while (*c)

{

v=n|(*c);

n+=0x100;

r= (int)((v>>2)^v)&0x0f;

ret=(ret(32-r));

ret&=0xFFFFFFFFL;

ret^=v*v;

c++;

}

 

return((ret>>16)^ret);

}MySql中出现的字符串Hash函数

 

#ifndef NEW_HASH_FUNCTION

 

/* Calc hashvalue for a key */

static uint calc_hashnr(const byte *key,uint length)

{

register uint nr=1, nr2=4;

 

while (length--)

{

nr^= (((nr & 63)+nr2)*((uint) (uchar) *key++))+ (nr << 8);

nr2+=3;

}

 

return((uint) nr);

}

 

/* Calc hashvalue for a key, case indepenently */

static uint calc_hashnr_caseup(const byte *key,uint length)

{

register uint nr=1, nr2=4;

 

while (length--)

{

nr^= (((nr & 63)+nr2)*((uint) (uchar) toupper(*key++)))+ (nr << 8);

nr2+=3;

}

 

return((uint) nr);

}

#else

/*

* Fowler/Noll/Vo hash

*

* The basis of the hash algorithm was taken from an idea sent by email to the

* IEEE Posix P1003.2 mailing list from Phong Vo (kpv@research.att.com) and

* Glenn Fowler (gsf@research.att.com). Landon Curt Noll (chongo@toad.com)

* later improved on their algorithm.

*

* The magic is in the interesting relationship between the special prime

* 16777619 (2^24 + 403) and 2^32 and 2^8.

*

* This hash produces the fewest collisions of any function that we've seen so

* far, and works well on both numbers and strings.

*/

uint calc_hashnr(const byte *key, uint len)

{

const byte *end=key+len;

uint hash;

 

for (hash = 0; key < end; key++)

{

hash *= 16777619;

hash ^= (uint) *(uchar*) key;

}

 

return (hash);

}

 

uint calc_hashnr_caseup(const byte *key, uint len)

{

const byte *end=key+len;

uint hash;

 

for (hash = 0; key < end; key++)

{

hash *= 16777619;

hash ^= (uint) (uchar) toupper(*key);

}

 

return (hash);

}

#endifMysql中对字符串Hash函数还区分了大小写

 

●另一个经典字符串Hash函数

 

unsigned int hash(char *str)

{

register unsigned int h;

register unsigned char *p;

 

for(h=0, p = (unsigned char *)str; *p ; p++)

h = 31 * h + *p;

 

return h;

}

posted on 2009-03-16 14:34  javamen  阅读(430)  评论(0编辑  收藏  举报