八数码 A*算法 和 数据结构

        没有办法,迫于兴趣,只好对以前写过的八数码问题进行重写,这次重写(A*依旧使用原来的估价方式估价)着重考虑 数据结构 的, 来提高执行效率。 

               通过测试,现在的八数码,执行效率还不错。  在此,把代码提供出来,一起学习~~ 不过,我把其写在同一个.cpp中(虽然这么做,不合理,但是我还是这么做了~) 该程序中:1:采用棋盘压缩   2:hash表判重  3: 路径记录通过hashtable中回溯   4:优先队列 用堆实现

       源代码如下(代码调试运行平台为:Microsoft Office 提供的 VC++6.0 编译器):

#include  < stdio.h >
#include 
< memory.h >
#include 
< windows.h >
#define  HashTableSize 260441  //  562147 460387 400249 360323 260441  
#define  HeapSize      5000
#define  MaxSteps      100
  
 
/**/ /*** 经过从  1 2 3 4 5 6 7 8 0 到  0 8 7 6 5 4 3 2 1 枚举测试,
      各个素数(HashTableSize) 的 hash 查询次数和表使用率如下: 

            素数      平均查询次数      使用率
           562147        1.22            32.3%
           460387        1.28            39.4%
           400249        1.36            45.3%
           360323        1.41            50.4%
           260441        1.75            70.0%
*/


/**/ /***
   这个棋盘采用4个字节表示。 
   其中 空格, 以及对应的 1~ 8 的数字, 用三个位表示, 然后 用四个位表示 空格的位置
   (这共花了 3 * 9 + 4  = 31 个位 )。
   注意棋盘是按 从上到下,从左到右, 依次标上编号:

                --------------
               | 00 | 01 | 02 |
                --------------
               | 03 | 04 | 05 |
                --------------
               | 06 | 07 | 08 |
                --------------
   
   棋盘表示法:
   000 : 1  , 001 : 2 , 010 : 3  
   011 : 4  , 100 : 5 , 101 : 6
   110 : 7  , 111 : 8 , 000 : 空格.
   注意: 有的这里 空格的位置 和 数码 1 的编码是一样,这并不矛盾, 因为实际上 空格编码可以删除,
   因为 后面要用 4 个位记录空格位置。 那么为什么还给 空格编码呢? 这主要是对压缩棋盘的上下左右
   移动更加方便。
   例如: 在 对下 棋盘:
       6 8 3 
       0 5 2
       4 7 1
   那么对应的Reduce_Map 编码是: 101  111  010  000  100  001  011  110  000   0011    0 
                                 ---  ---  ---  ---  ---  ---  ---  ---  ---   ----   ---
                                  6    8    3   空格  5    2    4    7    1      3   标志位
       
*/

/**/ /*** 棋盘数据结构 ****/

typedef 
struct  reduce ... {
public:
    unsigned  a00: 
3  ,  a01: 3 ,  a02: 3 ;
    unsigned  a03: 
3  ,  a04: 3 ,  a05: 3 ;
    unsigned  a06: 
3  ,  a07: 3 ,  a08: 3 ;
    unsigned  empty: 
4 ;   //  记录 空格的位置.
    unsigned  used:  1 ;  // 在 HashTable 元素中该位用来表示,是否已经占了。
    reduce():used(0)...{}
    
bool operator == (const reduce&  a);
}
Reduce_Map ;  

/**/ /**棋盘的表示**/
typedef 
struct   ... {
public:
    unsigned __int8 Board[
9];
    unsigned __int8 empty ; 
    
void print()
    
...{
        
for(int i =0 ; i < 9 ; i ++ )
        
...{
            
if(i%3 == 0 ) printf(" "); 
            printf(
"%5d",Board[i]);
        }

    }

}
Map ; 

/**/ /*****搜索的节点的表示******/
struct  Nodes ... {
public:
    Reduce_Map         RMap ;
    unsigned __int8       gx ;
    unsigned __int8       fx ;
//    unsigned short    hx ;   //  hx = fx - gx ;  
    unsigned int       parent ;   // 父节点, 在hash表中的位置
    unsigned int       index ;    // 该节点在hashtable中的位置
    Nodes():gx(0),fx(0)...{}
    
void Evaluate()...{}
}
;

/**/ /***栈:用来记录路径**/
struct  stacks ... {
public:
     __int8  length ; 
     Reduce_Map  path[MaxSteps];

     stacks():length(
-1)...{}
     
void       push(Reduce_Map& temp)...{  path[++length] = temp; }
     Reduce_Map pop()
...return path[length--] ; }
}
Stack;

/**/ /****hash表****/
struct  hashtable ... {
    Reduce_Map status ; 
    
int PreIndex ;                  // 用来记录 该节点的父节点在HashTable中对应的位置。
}
HashTable[HashTableSize];

/**/ /****优先队列******/
struct  PriorityQueue
... {
public:
     Nodes            Heap[HeapSize];    
// 堆数组
     int              bear ;             // 堆长度

     PriorityQueue():bear(
-1)...{}
     Nodes pop();
     
void  push(Nodes);
     
void  print();
     
bool  empty()...return (bear== -1);}
}
Queue;

void  inline swap(Nodes &   , Nodes & );
bool  inline compare( const  Nodes &  ,  const  Nodes & );

/**/ /*** 重载 == 运算符*****/
bool  reduce:: operator   == ( const  reduce &  a)
... {
     
static Reduce_Map temp ; 
     temp 
= a ; 
     temp.used 
= this->used ; 
     
if( memcmp( this , &temp , 4 ) == 0  ) return true ;
     
return false ; 
}


void  PriorityQueue::push(Nodes temp)
... {
      Heap[
++bear] = temp ; 
      
int k = bear, p ; 
      
while(k)
      
...{
          p 
= (k - 1 )>>1;
          
if( compare( Heap[k],Heap[p]) ) return ; 
          swap(Heap[k],Heap[p]);
          k 
= p ;
      }

      
return ;
}


Nodes PriorityQueue::pop()
... {
      
int flage , k = 0 , p ; 
      swap(Heap[
0],Heap[bear--]);
      
while( ( p = ( k << 1 ) ) < bear )
      
...{
          flage 
= 1
          
if( ( (p + 1< bear ) && compare( Heap[ p + 1 ] , Heap[ p + 2 ] ) ) flage ++ ;
          
if(compare( Heap[ p + flage ] , Heap[k] ) ) break ;
          swap(Heap[ p 
+ flage] , Heap[k]);
          k 
= p + flage ;
      }

      
return Heap[bear+1];
}


void  PriorityQueue::print()
... {
    
for(int i =0 ; i <= bear; i ++ )
        printf(
" fx:%d hx:%d ",Heap[i].fx , Heap[i].fx-Heap[i].gx);
    printf(
" ");
    getchar();
}



/**/ /**方格中不同位置之间的距离**/
static  unsigned __int8 Steps[ 9 ][ 9 ] = ... {
    
...0 , 1 , 2 , 1 , 2 , 3 , 2 , 3 , 4 } ,
    
...1 , 0 , 1 , 2 , 1 , 2 , 3 , 2 , 3 } ,
    
...2 , 1 , 0 , 3 , 2 , 1 , 4 , 3 , 2 } , 
    
...1 , 2 , 3 , 0 , 1 , 2 , 1 , 2 , 3 } ,
    
...2 , 1 , 2 , 1 , 0 , 1 , 2 , 1 , 2 } , 
    
...3 , 2 , 1 , 2 , 1 , 0 , 3 , 2 , 1 } ,
    
...2 , 3 , 4 , 1 , 2 , 3 , 0 , 1 , 2 } , 
    
...3 , 2 , 3 , 2 , 1 , 2 , 1 , 0 , 1 } ,
    
...4 , 3 , 2 , 3 , 2 , 1 , 2 , 1 , 0 }
}
;

/**/ /**两中目标状态***/
static  unsigned __int8 DlTarget[ 2 ][ 8 ] = ... {
    
...0 , 1 , 2 , 3 , 4 , 5 , 6 , 7  },
    
...0 , 1 , 2 , 5 , 8 , 7 , 6 , 3  }  
}
;

static  __int8    Derection[ 4 =   ... 1 , -1 , 3 , -3 }  ;
// static char   DeToChar[4] =  {'r', 'l','d', 'u'} ;

/**/ /******目标状态********/
static  unsigned __int8 Target[ 8 ] ;
 

bool  inline compare( const  Nodes &  Nodes1,  const  Nodes  & Nodes2)
... {
    
if(Nodes1.fx  > Nodes2.fx) return true ; 
    
if(Nodes1.fx  < Nodes2.fx) return false
    
return(Nodes1.gx  < Nodes2.gx); 
}


void  inline swap(Nodes &  a , Nodes & b)
... {
    Nodes c 
= b ; 
    b 
= a ; 
    a 
= c ;  
}


 
/**/ /*** 棋盘的压缩**/

inline 
void  ReduceTheMap(Map &  IMap , Reduce_Map &  RMap )
... {
     IMap.Board[IMap.empty] 
++ ; 
                      RMap.a00 
= IMap.Board[0- 1 , RMap.a01 = IMap.Board[1- 1 , RMap.a02 = IMap.Board[2- 1
     RMap.a03 
= IMap.Board[3- 1 , RMap.a04 = IMap.Board[4- 1 , RMap.a05 = IMap.Board[5- 1;
     RMap.a06 
= IMap.Board[6- 1 , RMap.a07 = IMap.Board[7- 1 , RMap.a08 = IMap.Board[8- 1;
     RMap.empty 
= IMap.empty ;
     IMap.Board[IMap.empty] 
-- ;
     
return ;
}


/**/ /*** 棋盘的解压**/
inline 
void  UnreduceMap(Map &  IMap ,  Reduce_Map &  RMap)
... {
          IMap.Board[
0= RMap.a00 + 1 , IMap.Board[1= RMap.a01 + 1 , IMap.Board[2= RMap.a02 + 1 ;
          IMap.Board[
3= RMap.a03 + 1 , IMap.Board[4= RMap.a04 + 1 , IMap.Board[5= RMap.a05 + 1 ;
          IMap.Board[
6= RMap.a06 + 1 , IMap.Board[7= RMap.a07 + 1 , IMap.Board[8= RMap.a08 + 1 ;
          IMap.empty 
= RMap.empty ;
          IMap.Board[IMap.empty] 
-- ; 
          
return ; 
}


/**/ /*** 判断是否查找过了(使用双散列函数探测法),
     函数返回该节点在hashtable中的位置,
     如果返回值为:-1 表示已经存在
*/

int  InsetHashTable(  Reduce_Map RMap ,  int  PreIndex  =   - 1  ) 
... {
    unsigned 
int Code;
    __asm                     
// 汇编实现同字节不同类型值的赋值:  Code = RMap 
    ...{
        mov eax,dword ptr[RMap]
        mov dword ptr[Code] ,eax
    }

    Code 
%= HashTableSize;

    
if(HashTable[Code].status.used == 0 ) // 如果used 为 0 ,表示 该处未被占用 
    ...
         HashTable[Code].status 
= RMap ; 
         HashTable[Code].status.used 
= 1 ;
         HashTable[Code].PreIndex 
= PreIndex ; // 记录父节点在hashtable中的位置,便于回溯找路径
         return Code ; 
    }

    
if( HashTable[Code].status == RMap )  return -1 ; 
    
    unsigned 
int temp = Code | RMap.empty;   // 经过测试,这样简单操作后,使得二次探测碰撞减少了些~~

    
while(HashTable[Code].status.used == 1 )...{
         Code 
+= temp ;
         
if(Code >= HashTableSize) Code -= HashTableSize ;
         
if( HashTable[Code].status == RMap ) return -1 ; 
    }

    HashTable[Code].status 
= RMap ; 
                     HashTable[Code].status.used 
= 1 ; 
    HashTable[Code].PreIndex 
= PreIndex ; 
    
return Code ; 
}


/**/ /***对 hx 的估价(使用的是: 每个数码到目标位置的距离 之和 ) ***/
inline 
void  Evaluate(Nodes &  one)
... {
           one.fx 
= - Steps[ one.RMap.empty ][ Target[ 0 ] ] ; 
           one.fx 
+= Steps[ 0 ][ Target[ one.RMap.a00 ] ] + Steps[ 1 ][ Target[ one.RMap.a01 ] ] +
           Steps[ 
2 ][ Target[ one.RMap.a02 ] ] + Steps[ 3 ][ Target[ one.RMap.a03 ] ] +
           Steps[ 
4 ][ Target[ one.RMap.a04 ] ] + Steps[ 5 ][ Target[ one.RMap.a05 ] ] +
           Steps[ 
6 ][ Target[ one.RMap.a06 ] ] + Steps[ 7 ][ Target[ one.RMap.a07 ] ] +
           Steps[ 
8 ][ Target[ one.RMap.a08 ] ] ;
           one.fx 
+= one.gx ; 
}


/**/ /****回溯找出路径***/
void  FindFinalPath(unsigned  int &  ObjIndex )
... {
           
int temp = ObjIndex ; 
           
while(temp != -1 )
    
...{
                Stack.push(HashTable[temp].status);
                temp 
= HashTable[temp].PreIndex;
            }

    
return ;
}


void  search(Nodes begin ) ...
    Nodes one , now ; 
    
int temp , flage ; 
    Queue.push(begin);
    
while!Queue.empty() )...{
        now 
= Queue.pop();
        
if(now.gx == now.fx ) 
        
...{
            FindFinalPath(now.index); 
            
return ;
        }

        
for(int k =0 ; k < 4; k ++ )
        
...{
            temp 
= now.RMap.empty + Derection[k] ; 
            
if(temp >=0 && temp< 9 && Steps[temp][now.RMap.empty] == 1 ) 
            
...
                one.RMap 
= now.RMap ;
                one.RMap.empty 
= temp;
                __asm                        
// 由于这里RMap 被定义为struct 类型, 因此移动很不方便,所以只好采用汇编了
                ...{
                    ; 把one.RMap.empty 空格的位置取出(即移动后 空格所在位置)
                    mov    ecx , dword ptr[one.RMap]
                    shr    ecx , 
27       ; 0000001bH
                    ;and    ecx , 
15       ; 0000000fH

                    ; 把one.RMap中的要移动的数码取出,并把该位清零
----“空格”~
                    imul   ecx , 
3
                    mov    ebx , 
7 
                    shl    ebx , cl
                    mov    eax , ebx
                    and    ebx , dword ptr[one.RMap]   ; 把数码取出放在 ebx 中
                    shr    ebx , cl 

                    not    eax
                    and    dword ptr[one.RMap],  eax   ; 把该位清零
----“空格”操作

                    ; 把now.RMap.empty 空格的位置取出(即移动前,空格所在位置)
                    mov    ecx , dword ptr[now.RMap]
                    shr    ecx , 
27       ; 0000001bH
                    ;and    ecx , 
15       ; 0000000fH

                    ; 把取出的数码移到空格位置上去
                    imul   ecx , 
3
                    shl    ebx , cl
                    or     dword ptr[one.RMap] , ebx 
                }

                flage 
= InsetHashTable( one.RMap , now.index );
                                    
if( flage >= 0 ) 
                
...{
                    one.gx 
= now.gx +1 ;
                    Evaluate(one);
                    one.parent 
= now.index ; 
                    one.index 
= flage ; 
                                                       Queue.push(one);
                }

            }

        }

    }

}


void  input(Nodes &  begin)
... {
    
int i ,j ; 
    
int sum =0 , k ; 
    Map temp ; 
    printf(
"请输入相应八数码的位置: ");
                     
for(i =0 ;i  < 9 ; i ++ )...{
        scanf(
"%I8d",&temp.Board[i]);
        
if(temp.Board[i] == 0 ) 
        
...{
            k 
= i ; 
            
continue;
        }

        
for(j =0 ; j< i ; j ++ )
            
if(temp.Board[j] > temp.Board[i]) sum ++ ; 
    }

    temp.empty 
= k ; 

    ReduceTheMap(temp,begin.RMap);

    
if(sum%2) memcpy(Target,DlTarget[1],8);
    
else memcpy(Target,DlTarget[0],8);

    Evaluate(begin);
    begin.index 
= InsetHashTable(begin.RMap);
    
return ;
}


void  output() ... {
   
if(Stack.length <= 0 ) printf("已经是目标状态了,你这不是自找麻烦嘛! ");
   
else 
   
...{
        Map temp ;
        printf(
"搞定!  供需 %d 步 , 步骤如下: ",Stack.length );
        
for(int i =Stack.length ; i >= 0 ; i --  )
        
...{
            UnreduceMap( temp , Stack.pop());
            temp.print();
            getchar();
            
if(i) printf(" ----> ");
        }

   }

   printf(
" ");
   
return ;
}


int  main()
... {
     Nodes begin ; 
     input(begin);
     
long time = GetTickCount();
     search(begin);
     printf(
"计算耗时:%dMS ",GetTickCount()-time);
     output();
     
return 0 ; 
}

运行效果为:

  

 为了便于复制代码(因此便有下面的了):

#include <stdio.h>
#include <memory.h>
#include <windows.h>
#define HashTableSize 260441 // 562147 460387 400249 360323 260441 
#define HeapSize      5000
#define MaxSteps      100
 
 /*** 经过从  1 2 3 4 5 6 7 8 0 到  0 8 7 6 5 4 3 2 1 枚举测试,
      各个素数(HashTableSize) 的 hash 查询次数和表使用率如下:

         素数      平均查询次数      使用率
        562147        1.22            32.3%
     460387        1.28            39.4%
     400249        1.36            45.3%
     360323        1.41            50.4%
     260441        1.75            70.0%
*/

/***
   这个棋盘采用4个字节表示。
   其中 空格, 以及对应的 1~ 8 的数字, 用三个位表示, 然后 用四个位表示 空格的位置
   (这共花了 3 * 9 + 4  = 31 个位 )。
   注意棋盘是按 从上到下,从左到右, 依次标上编号:

                --------------
               | 00 | 01 | 02 |
                --------------
               | 03 | 04 | 05 |
                --------------
               | 06 | 07 | 08 |
                --------------
  
   棋盘表示法:
   000 : 1  , 001 : 2 , 010 : 3 
   011 : 4  , 100 : 5 , 101 : 6
   110 : 7  , 111 : 8 , 000 : 空格.
   注意: 有的这里 空格的位置 和 数码 1 的编码是一样,这并不矛盾, 因为实际上 空格编码可以删除,
   因为 后面要用 4 个位记录空格位置。 那么为什么还给 空格编码呢? 这主要是对压缩棋盘的上下左右
   移动更加方便。
   例如: 在 对下 棋盘:
       6 8 3
    0 5 2
    4 7 1
   那么对应的Reduce_Map 编码是: 101  111  010  000  100  001  011  110  000   0011    0
                                 ---  ---  ---  ---  ---  ---  ---  ---  ---   ----   ---
          6    8    3   空格  5    2    4    7    1      3   标志位
      
*/
/*** 棋盘数据结构 ****/

扫描二维码关注公众号,回复: 3793368 查看本文章

typedef struct reduce{
public:
    unsigned  a00: 3  ,  a01: 3 ,  a02: 3 ;
 unsigned  a03: 3  ,  a04: 3 ,  a05: 3 ;
 unsigned  a06: 3  ,  a07: 3 ,  a08: 3 ;
 unsigned  empty: 4 ;   //  记录 空格的位置.
 unsigned  used:  1 ;  // 在 HashTable 元素中该位用来表示,是否已经占了。
 reduce():used(0){}
 bool operator == (const reduce&  a);
}Reduce_Map ; 

/**棋盘的表示**/
typedef struct {
public:
    unsigned __int8 Board[9];
 unsigned __int8 empty ;
 void print()
 {
  for(int i =0 ; i < 9 ; i ++ )
  {
   if(i%3 == 0 ) printf("/n");
   printf("%5d",Board[i]);
  }
 }
}Map ;

/*****搜索的节点的表示******/
struct Nodes{
public:
    Reduce_Map         RMap ;
 unsigned __int8       gx ;
 unsigned __int8       fx ;
// unsigned short    hx ;   //  hx = fx - gx ; 
 unsigned int       parent ;   // 父节点, 在hash表中的位置
 unsigned int       index ;    // 该节点在hashtable中的位置
 Nodes():gx(0),fx(0){}
 void Evaluate(){}
};

/***栈:用来记录路径**/
struct stacks{
public:
     __int8  length ;
  Reduce_Map  path[MaxSteps];

  stacks():length(-1){}
  void       push(Reduce_Map& temp){  path[++length] = temp; }
  Reduce_Map pop(){ return path[length--] ; }
}Stack;

/****hash表****/
struct hashtable{
 Reduce_Map status ;
 int PreIndex ;                  // 用来记录 该节点的父节点在HashTable中对应的位置。
}HashTable[HashTableSize];

/****优先队列******/
struct PriorityQueue
{
public:
     Nodes            Heap[HeapSize];    // 堆数组
  int              bear ;             // 堆长度

     PriorityQueue():bear(-1){}
  Nodes pop();
  void  push(Nodes);
  void  print();
  bool  empty(){ return (bear== -1);}
}Queue;

void inline swap(Nodes&  , Nodes&);
bool inline compare(const Nodes& , const Nodes&);

/*** 重载 == 运算符*****/
bool reduce::operator ==(const reduce& a)
{
  static Reduce_Map temp ;
  temp = a ;
  temp.used = this->used ;
     if( memcmp( this , &temp , 4 ) == 0  ) return true ;
  return false ;
}

void PriorityQueue::push(Nodes temp)
{
      Heap[++bear] = temp ;
      int k = bear, p ;
   while(k)
   {
    p = (k - 1 )>>1;
    if( compare( Heap[k],Heap[p]) ) return ;
    swap(Heap[k],Heap[p]);
    k = p ;
   }
   return ;
}

Nodes PriorityQueue::pop()
{
   int flage , k = 0 , p ;
      swap(Heap[0],Heap[bear--]);
      while( ( p = ( k << 1 ) ) < bear )
   {
    flage = 1;
    if( ( (p + 1) < bear ) && compare( Heap[ p + 1 ] , Heap[ p + 2 ] ) ) flage ++ ;
    if(compare( Heap[ p + flage ] , Heap[k] ) ) break ;
    swap(Heap[ p + flage] , Heap[k]);
    k = p + flage ;
   }
   return Heap[bear+1];
}

void PriorityQueue::print()
{
    for(int i =0 ; i <= bear; i ++ )
  printf("/tfx:%d hx:%d/t/n",Heap[i].fx , Heap[i].fx-Heap[i].gx);
 printf("/n");
 getchar();
}


/**方格中不同位置之间的距离**/
static unsigned __int8 Steps[9][9]={
    { 0 , 1 , 2 , 1 , 2 , 3 , 2 , 3 , 4 } ,
 { 1 , 0 , 1 , 2 , 1 , 2 , 3 , 2 , 3 } ,
 { 2 , 1 , 0 , 3 , 2 , 1 , 4 , 3 , 2 } ,
 { 1 , 2 , 3 , 0 , 1 , 2 , 1 , 2 , 3 } ,
 { 2 , 1 , 2 , 1 , 0 , 1 , 2 , 1 , 2 } ,
 { 3 , 2 , 1 , 2 , 1 , 0 , 3 , 2 , 1 } ,
 { 2 , 3 , 4 , 1 , 2 , 3 , 0 , 1 , 2 } ,
 { 3 , 2 , 3 , 2 , 1 , 2 , 1 , 0 , 1 } ,
 { 4 , 3 , 2 , 3 , 2 , 1 , 2 , 1 , 0 }
};

/**两中目标状态***/
static unsigned __int8 DlTarget[2][8]={
    { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7  },
 { 0 , 1 , 2 , 5 , 8 , 7 , 6 , 3  } 
};

static __int8    Derection[4] = { 1 , -1 , 3 , -3 } ;
//static char   DeToChar[4] =  {'r', 'l','d', 'u'} ;

/******目标状态********/
static unsigned __int8 Target[8] ;
 

bool inline compare(const Nodes& Nodes1, const Nodes &Nodes2)
{
    if(Nodes1.fx  > Nodes2.fx) return true ;
    if(Nodes1.fx  < Nodes2.fx) return false;
 return(Nodes1.gx  < Nodes2.gx);
}

void inline swap(Nodes& a , Nodes&b)
{
 Nodes c = b ;
 b = a ;
 a = c ; 
}

 /*** 棋盘的压缩**/

inline void ReduceTheMap(Map& IMap , Reduce_Map& RMap )
{
  IMap.Board[IMap.empty] ++ ;
     RMap.a00 = IMap.Board[0] - 1 , RMap.a01 = IMap.Board[1] - 1 , RMap.a02 = IMap.Board[2] - 1;
  RMap.a03 = IMap.Board[3] - 1 , RMap.a04 = IMap.Board[4] - 1 , RMap.a05 = IMap.Board[5] - 1;
  RMap.a06 = IMap.Board[6] - 1 , RMap.a07 = IMap.Board[7] - 1 , RMap.a08 = IMap.Board[8] - 1;
  RMap.empty = IMap.empty ;
  IMap.Board[IMap.empty] -- ;
  return ;
}

/*** 棋盘的解压**/
inline void UnreduceMap(Map& IMap ,  Reduce_Map& RMap)
{
     IMap.Board[0] = RMap.a00 + 1 , IMap.Board[1] = RMap.a01 + 1 , IMap.Board[2] = RMap.a02 + 1 ;
     IMap.Board[3] = RMap.a03 + 1 , IMap.Board[4] = RMap.a04 + 1 , IMap.Board[5] = RMap.a05 + 1 ;
  IMap.Board[6] = RMap.a06 + 1 , IMap.Board[7] = RMap.a07 + 1 , IMap.Board[8] = RMap.a08 + 1 ;
  IMap.empty = RMap.empty ;
  IMap.Board[IMap.empty] -- ;
  return ;
}

/*** 判断是否查找过了(使用双散列函数探测法),
     函数返回该节点在hashtable中的位置,
     如果返回值为:-1 表示已经存在
*/
int InsetHashTable(  Reduce_Map RMap , int PreIndex = -1 )
{
    unsigned int Code;
 __asm                     // 汇编实现同字节不同类型值的赋值:  Code = RMap
 {
  mov eax,dword ptr[RMap]
  mov dword ptr[Code] ,eax
 }
 Code %= HashTableSize;

 if(HashTable[Code].status.used == 0 ) // 如果used 为 0 ,表示 该处未被占用
 {
   HashTable[Code].status = RMap ;
      HashTable[Code].status.used = 1 ;
   HashTable[Code].PreIndex = PreIndex ; // 记录父节点在hashtable中的位置,便于回溯找路径
   return Code ;
 }
 if( HashTable[Code].status == RMap )  return -1 ;
 
    unsigned int temp = Code | RMap.empty;   // 经过测试,这样简单操作后,使得二次探测碰撞减少了些~~

 while(HashTable[Code].status.used == 1 ){
   Code += temp ;
   if(Code >= HashTableSize) Code -= HashTableSize ;
   if( HashTable[Code].status == RMap ) return -1 ;
 }
 HashTable[Code].status = RMap ;
    HashTable[Code].status.used = 1 ;
 HashTable[Code].PreIndex = PreIndex ;
 return Code ;
}

/***对 hx 的估价(使用的是: 每个数码到目标位置的距离 之和 ) ***/
inline void Evaluate(Nodes& one)
{
    one.fx = - Steps[ one.RMap.empty ][ Target[ 0 ] ] ;
 one.fx += Steps[ 0 ][ Target[ one.RMap.a00 ] ] + Steps[ 1 ][ Target[ one.RMap.a01 ] ] +
        Steps[ 2 ][ Target[ one.RMap.a02 ] ] + Steps[ 3 ][ Target[ one.RMap.a03 ] ] +
        Steps[ 4 ][ Target[ one.RMap.a04 ] ] + Steps[ 5 ][ Target[ one.RMap.a05 ] ] +
        Steps[ 6 ][ Target[ one.RMap.a06 ] ] + Steps[ 7 ][ Target[ one.RMap.a07 ] ] +
        Steps[ 8 ][ Target[ one.RMap.a08 ] ] ;
 one.fx += one.gx ;
}

/****回溯找出路径***/
void FindFinalPath(unsigned int& ObjIndex )
{
 int temp = ObjIndex ;
 while(temp != -1 )
 {
  Stack.push(HashTable[temp].status);
  temp = HashTable[temp].PreIndex;
 }
 return ;
}

void search(Nodes begin ){
    Nodes one , now ;
 int temp , flage ;
 Queue.push(begin);
 while( !Queue.empty() ){
  now = Queue.pop();
  if(now.gx == now.fx )
  {
   FindFinalPath(now.index);
   return ;
  }
  for(int k =0 ; k < 4; k ++ )
  {
      temp = now.RMap.empty + Derection[k] ;
   if(temp >=0 && temp< 9 && Steps[temp][now.RMap.empty] == 1 )
   {
       one.RMap = now.RMap ;
       one.RMap.empty = temp;
       __asm                        // 由于这里RMap 被定义为struct 类型, 因此移动很不方便,所以只好采用汇编了
    {
        ; 把one.RMap.empty 空格的位置取出(即移动后 空格所在位置)
        mov    ecx , dword ptr[one.RMap]
        shr    ecx , 27       ; 0000001bH
        ;and    ecx , 15       ; 0000000fH

        ; 把one.RMap中的要移动的数码取出,并把该位清零----“空格”~
                    imul   ecx , 3
        mov    ebx , 7
        shl    ebx , cl
                    mov    eax , ebx
        and    ebx , dword ptr[one.RMap]   ; 把数码取出放在 ebx 中
        shr    ebx , cl

        not    eax
        and    dword ptr[one.RMap],  eax   ; 把该位清零----“空格”操作

        ; 把now.RMap.empty 空格的位置取出(即移动前,空格所在位置)
        mov    ecx , dword ptr[now.RMap]
        shr    ecx , 27       ; 0000001bH
        ;and    ecx , 15       ; 0000000fH

        ; 把取出的数码移到空格位置上去
        imul   ecx , 3
        shl    ebx , cl
        or     dword ptr[one.RMap] , ebx
    }
    flage = InsetHashTable( one.RMap , now.index );
       if( flage >= 0 )
    {
     one.gx = now.gx +1 ;
     Evaluate(one);
     one.parent = now.index ;
     one.index = flage ;
           Queue.push(one);
    }
   }
  }
 }
}

void input(Nodes& begin)
{
 int i ,j ;
 int sum =0 , k ;
 Map temp ;
 printf("请输入相应八数码的位置:/n");
    for(i =0 ;i  < 9 ; i ++ ){
  scanf("%I8d",&temp.Board[i]);
  if(temp.Board[i] == 0 )
  {
   k = i ;
   continue;
  }
  for(j =0 ; j< i ; j ++ )
   if(temp.Board[j] > temp.Board[i]) sum ++ ;
 }
 temp.empty = k ;

 ReduceTheMap(temp,begin.RMap);

 if(sum%2) memcpy(Target,DlTarget[1],8);
 else memcpy(Target,DlTarget[0],8);

 Evaluate(begin);
 begin.index = InsetHashTable(begin.RMap);
 return ;
}

void output(){
   if(Stack.length <= 0 ) printf("已经是目标状态了,你这不是自找麻烦嘛!/n");
   else
   {
     Map temp ;
        printf("搞定!/t 供需 %d 步 , 步骤如下:/n",Stack.length );
  for(int i =Stack.length ; i >= 0 ; i --  )
  {
   UnreduceMap( temp , Stack.pop());
   temp.print();
   getchar();
   if(i) printf("/n/n---->/n");
  }
   }
   printf("/n");
   return ;
}

int main()
{
     Nodes begin ;
  input(begin);
  long time = GetTickCount();
  search(begin);
  printf("计算耗时:%dMS/n",GetTickCount()-time);
  output();
  return 0 ;
}

猜你喜欢

转载自blog.csdn.net/destiny_AC/article/details/1911669
今日推荐