现在的位置: 首页 > 综合 > 正文

网上的资料

2013年04月25日 ⁄ 综合 ⁄ 共 30629字 ⁄ 字号 评论关闭
 

 图的遍历和生成树求解实现(邻接矩阵、邻接表 —图的深度广度遍历算法的实现和最小生成树PRIM和KRUSCAL算法的实现)

#include <iostream>
#include <malloc.h>
using namespace std;
#define int_max 10000
#define inf 9999
#define max 20
//…………………………………………邻接矩阵定义……………………
typedef struct ArcCell
{
 int adj;
 char *info;
}ArcCell,AdjMatrix[20][20];
typedef struct
{
 char vexs[20];
 AdjMatrix arcs;
 int vexnum,arcnum;
}MGraph_L;
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
int localvex(MGraph_L G,char v)//返回V的位置
{
 int i=0;
 while(G.vexs[i]!=v)
 {
  ++i;
 }
 return i;
}

int creatMGraph_L(MGraph_L &G)//创建图用邻接矩阵表示
{
 char v1,v2;
 int i,j,w;
 cout<<"…………创建无向图…………"<<endl<<"请输入图G顶点和弧的个数:(4 6)不包括“()”"<<endl;
 cin>>G.vexnum>>G.arcnum;
 for(i=0;i!=G.vexnum;++i)
 {
  cout<<"输入顶点"<<i<<endl;
  cin>>G.vexs[i];
 }
 for(i=0;i!=G.vexnum;++i)
  for(j=0;j!=G.vexnum;++j)
  { 
   G.arcs[i][j].adj=int_max;
   G.arcs[i][j].info=NULL;
  }
 for(int k=0;k!=G.arcnum;++k)
  { 
   cout<<"输入一条边依附的顶点和权:(a b 3)不包括“()”"<<endl;
   cin>>v1>>v2>>w;//输入一条边依附的两点及权值
   i=localvex(G,v1);//确定顶点V1和V2在图中的位置
   j=localvex(G,v2);
   G.arcs[i][j].adj=w;
   G.arcs[j][i].adj=w;
  }
  cout<<"图G邻接矩阵创建成功!"<<endl;
  return G.vexnum;
}
void ljjzprint(MGraph_L G)
{
 int i,j;
 for(i=0;i!=G.vexnum;++i)
  {
   for(j=0;j!=G.vexnum;++j)
    cout<<G.arcs[i][j].adj<<" ";
   cout<<endl;
  }
}
int visited[max];//访问标记
int we;
typedef struct arcnode//弧结点
{
 int adjvex;//该弧指向的顶点的位置
 struct arcnode *nextarc;//弧尾相同的下一条弧
 char *info;//该弧信息
}arcnode;
typedef struct vnode//邻接链表顶点头接点
{
 char data;//结点信息
 arcnode *firstarc;//指向第一条依附该结点的弧的指针
}vnode,adjlist;
typedef struct//图的定义
{
 adjlist vertices[max];
 int vexnum,arcnum;
 int kind;
}algraph;
//…………………………………………队列定义……………………
typedef struct qnode
{
 int data;
 struct qnode *next;

}qnode,*queueptr;

typedef struct
{
 queueptr front;
 queueptr rear;

}linkqueue;
//………………………………………………………………………
typedef struct acr
{
 int pre;//弧的一结点
 int bak;//弧另一结点
 int weight;//弧的权
}edg;

int creatadj(algraph &gra,MGraph_L G)//用邻接表存储图
{
  
 int i=0,j=0;
 arcnode *arc,*tem,*p;
 for(i=0;i!=G.vexnum;++i)
 {
  gra.vertices[i].data=G.vexs[i];
  gra.vertices[i].firstarc=NULL;
 }
 for(i=0;i!=G.vexnum;++i)
 {
  for(j=0;j!=G.vexnum;++j)
  {
   if(gra.vertices[i].firstarc==NULL)
   {
    if(G.arcs[i][j].adj!=int_max&&j!=G.vexnum)
    {
     arc=(arcnode *)malloc(sizeof(arcnode));
     arc->adjvex=j;
     gra.vertices[i].firstarc=arc;
     arc->nextarc=NULL;
     p=arc;
     ++j;
     while(G.arcs[i][j].adj!=int_max&&j!=G.vexnum)
     {
      tem=(arcnode *)malloc(sizeof(arcnode));
      tem->adjvex=j;    
      gra.vertices[i].firstarc=tem;
      tem->nextarc=arc;
      arc=tem;
      ++j;
     }
     --j;
    }
   }
   else
   {
    if(G.arcs[i][j].adj!=int_max&&j!=G.vexnum)
    {
     arc=(arcnode *)malloc(sizeof(arcnode));
     arc->adjvex=j;
     p->nextarc=arc;
     arc->nextarc=NULL;
     p=arc;
    }

   }
 
  }
 }
 gra.vexnum=G.vexnum;
 gra.arcnum=G.arcnum;

 /*for(i=0;i!=gra.vexnum;++i)
 {
  arcnode *p;
  cout<<i<<" ";
  p=gra.vertices[i].firstarc;
  while(p!=NULL)
  {
   cout<<p->adjvex;
   p=p->nextarc;
  }
  cout<<endl;

 }*/
  cout<<"图G邻接表创建成功!"<<endl;
 return 1;
}
void adjprint(algraph gra)
{
 int i;
 for(i=0;i!=gra.vexnum;++i)
 {
  arcnode *p;
  cout<<i<<" ";
  p=gra.vertices[i].firstarc;
  while(p!=NULL)
  {
   cout<<p->adjvex;
   p=p->nextarc;
  }
  cout<<endl;
 }
}

int firstadjvex(algraph gra,vnode v)//返回依附顶点V的第一个点
         //即以V为尾的第一个结点
{
 if(v.firstarc!=NULL)
 return v.firstarc->adjvex;

}
int nextadjvex(algraph gra,vnode v,int w)//返回依附顶点V的相对于W的下一个顶点
{
 arcnode *p;
 p=v.firstarc;
 while(p!=NULL&&p->adjvex!=w)
 {
   p=p->nextarc;
 }
  if(p->adjvex==w&&p->nextarc!=NULL)
  {
   p=p->nextarc;
    return p->adjvex;
  }
  if(p->adjvex==w&&p->nextarc==NULL)
  return -10;
 
}
int initqueue(linkqueue &q)//初始化队列
{
 q.rear=(queueptr)malloc(sizeof(qnode));
 q.front=q.rear;
 if(!q.front)
  return 0;
 q.front->next=NULL;
 return 1;
}
int enqueue(linkqueue &q,int e)//入队
{
 queueptr p;
 p=(queueptr)malloc(sizeof(qnode));
 if(!p)
  return 0;
 p->data=e;
 p->next=NULL;
 q.rear->next=p;
 q.rear=p;
 return 1;

}
int dequeue(linkqueue &q,int &e)//出队
{
 queueptr p;
 if(q.front==q.rear)
  return 0;
 p=q.front->next;
 e=p->data;
 q.front->next=p->next;
 if(q.rear==p)
  q.rear=q.front;
 free(p);
 return 1;

}
int queueempty(linkqueue q)//判断队为空
{
 if(q.front==q.rear)
  return 1;
 return 0;
}
void bfstra(algraph gra)//广度优先遍历
{
 int i,e;
 linkqueue q;
 for(i=0;i!=gra.vexnum;++i)
  visited[i]=0;
 initqueue(q);
 for(i=0;i!=gra.vexnum;++i)

  if(!visited[i])
  { visited[i]=1;
   cout<<gra.vertices[i].data;
   enqueue(q,i);
   while(!queueempty(q))
   {
    dequeue(q,e);
   // cout<<" "<<e<<" ";
    for(we=firstadjvex(gra,gra.vertices[e]);we>=0;we=nextadjvex(gra,gra.vertices[e],we))
    {
     if(!visited[we])
     {
      visited[we]=1;
      cout<<gra.vertices[we].data;
      enqueue(q,we);
     }
    }
   }
  }
}

int dfs(algraph gra,int i);//声明DFS

int dfstra(algraph gra)
{
 int i,j;
 for(i=0;i!=gra.vexnum;++i)
 {
  visited[i]=0;
 }
 for(j=0;j!=gra.vexnum;++j)
 {
  if(visited[j]==0)
   dfs(gra,j);
}
 return 0;
}
int dfs(algraph gra,int i)
{
 visited[i]=1;
 int we1;
// cout<<i<<visited[i]<<endl;
 cout<<gra.vertices[i].data;
// cout<<endl;
 for(we=firstadjvex(gra,gra.vertices[i]);we>=0;we=nextadjvex(gra,gra.vertices[i],we))
 {
 // cout<<we<<visited[we]<<endl;
  we1=we;
 // cout<<nextadjvex(gra,gra.vertices[i],we)<<endl;
  if(visited[we]==0)
 //  cout<<
   dfs(gra,we);//<<endl;
 // cout<<i<<we1<<endl;
  we=we1;
 // cout<<nextadjvex(gra,gra.vertices[i],we)<<endl;  
 }
 return 12;
}
int bfstra_fen(algraph gra)//求连通分量
{
 int i,j;
 for(i=0;i!=gra.vexnum;++i)
 {
  visited[i]=0;
 }
 for(j=0;j!=gra.vexnum;++j)
 {
  if(visited[j]==0)
  {
   dfs(gra,j);
   cout<<endl;
  }
 }
 return 0;
}

typedef struct
 {
  int adjvex;
  int lowcost;
 }closedge;
/*int minimum(closedge *p);
int minispantree(MGraph_L G,char u)
{
 
 int k,j,i;
 closedge closedge_a[20];
 k=localvex(G,u);
// cout<<k<<endl;
 for(j=0;j!=G.vexnum;++j)
 {
  if(j!=k)
  { 
   closedge_a[j].adjvex=u;
   closedge_a[j].lowcost=G.arcs[k][j].adj;
  }
  for(i=1;i!=G.vexnum;++i)
  {
   k=minimum(closedge_a);
   cout<<k;
   cout<<closedge_a[k].adjvex<<" "<<G.vexs[k]<<endl;
   closedge_a[k].lowcost=0;
   for(j=0;j!=G.vexnum;++j)
    if(G.arcs[k][j].adj<closedge_a[j].lowcost)
     { 
      closedge_a[j].adjvex=G.vexs[k];
      closedge_a[j].lowcost=G.arcs[k][j].adj;
     }

  }
 }
 return 0;
}
int minimum(closedge *p)
{
 int s=10000;
 for(;p!=NULL;++p)
 {
  if(s>p->lowcost)
   s=p->lowcost;
 }
 return s;

}*/
int prim(int g[][max],int n) //最小生成树PRIM算法
{
 int lowcost[max],prevex[max]; //LOWCOST[]存储当前集合U分别到剩余结点的最短路径
         //prevex[]存储最短路径在U中的结点
 int i,j,k,min;
 for(i=2;i<=n;i++) //n个顶点,n-1条边
 {
  lowcost[i]=g[1][i]; //初始化
  prevex[i]=1; //顶点未加入到最小生成树中
 }
 lowcost[1]=0; //标志顶点1加入U集合
 for(i=2;i<=n;i++) //形成n-1条边的生成树
 {
  min=inf;
  k=0;
  for(j=2;j<=n;j++) //寻找满足边的一个顶点在U,另一个顶点在V的最小边
   if((lowcost[j]<min)&&(lowcost[j]!=0))
   {
    min=lowcost[j];
    k=j;
   }
  printf("(%d,%d)%d/t",prevex[k]-1,k-1,min);
  lowcost[k]=0; //顶点k加入U
  for(j=2;j<=n;j++) //修改由顶点k到其他顶点边的权值
   if(g[k][j]<lowcost[j])
   {
    lowcost[j]=g[k][j];
    prevex[j]=k;
   }
  printf("/n");
 } 
return 0;
}
int acrvisited[100];//kruscal弧标记数组
int find(int acrvisited[],int f)
{
 while(acrvisited[f]>0)
  f=acrvisited[f];
 return f;
}
void kruscal_arc(MGraph_L G,algraph gra)

 edg edgs[20];
 int i,j,k=0;
 for(i=0;i!=G.vexnum;++i)
  for(j=i;j!=G.vexnum;++j)
  {
   if(G.arcs[i][j].adj!=10000)
   {
    edgs[k].pre=i;
    edgs[k].bak=j;
    edgs[k].weight=G.arcs[i][j].adj;
    ++k;
   }
  }
 int x,y,m,n;
 int buf,edf;
 for(i=0;i!=gra.arcnum;++i)
  acrvisited[i]=0; 
 for(j=0;j!=G.arcnum;++j)
 {
  m=10000;
  for(i=0;i!=G.arcnum;++i)
  {
   if(edgs[i].weight<m)
   {
    m=edgs[i].weight;
    x=edgs[i].pre;
    y=edgs[i].bak;
    n=i;
   }
   
  }
//  cout<<x<<y<<m;
//  cout<<endl;
   buf=find(acrvisited,x);
   edf=find(acrvisited,y); 
//   cout<<buf<<" "<<edf<<endl;
   edgs[n].weight=10000;
   if(buf!=edf)
   {
    acrvisited[buf]=edf;
    
    cout<<"("<<x<<","<<y<<")"<<m;
    cout<<endl;
   }
 }
 
}

void main()

 algraph gra;
 MGraph_L G;
 int i,d,g[20][20];
 char a='a';
 d=creatMGraph_L(G);
 creatadj(gra,G);
 vnode v;
 cout<<endl<<"……####注意:若该图为非强连通图(含有多个连通分量)时"<<endl
  <<"      最小生成树不存在,则显示为非法值。"<<endl<<endl;
 cout<<"…………………菜单……………………"<<endl<<endl;
 cout<<"0、显示该图的邻接矩阵……………………"<<endl;
 cout<<"1、显示该图的邻接表……………………"<<endl;
 cout<<"2、深度优先遍历…………………………"<<endl;
 cout<<"3、广度优先遍历…………………………"<<endl;
 cout<<"4、最小生成树PRIM算法…………………"<<endl;
 cout<<"5、最小生成树KRUSCAL算法………………"<<endl;
 cout<<"6、该图的连通分量………………………"<<endl<<endl;
 int s;
 char y='y';
 while(y='y')
 {
  cout<<"请选择菜单:"<<endl;
  cin>>s;
  switch(s)
  {
  case 0:
   cout<<"邻接矩阵显示如下:"<<endl;
   ljjzprint(G);
   break;
  case 1:
   cout<<"邻接表显示如下:"<<endl;
   adjprint(gra);
   break;
  case 2:
   cout<<"广度优先遍历:";
   bfstra(gra);
   cout<<endl;
   break;
  case 3:
   for(i=0;i!=gra.vexnum;++i)
    {
    visited[i]=0;
   }
   cout<<"深度优先遍历:"; 
   dfstra(gra);
   cout<<endl;
   break;
  case 4:
   for(i=0;i!=G.vexnum;++i)
    for(int j=0;j!=G.vexnum;++j)
     g[i+1][j+1]=G.arcs[i][j].adj;
   cout<<"prim:"<<endl;
   prim(g,d);
   break;
  case 5:
   cout<<"kruscal:"<<endl;
   kruscal_arc(G,gra);
   break;
  case 6:
   cout<<"连通分量:";
   bfstra_fen(gra);
  break;

  }
  cout<<endl<<"是否继续?y/n:";
   cin>>y;
  if(y=='n')
   break;
 }

 绝对经典 C++初学者必看的50个建议

  2.看《Thinking In C++》,不要看《C++变成死相》;

  3.看《The C++ Programming Language》和《Inside The C++ Object Model》,不要因为他们很难而我们自己是初学者所以就不看;

  4.不要被VC、BCB、BC、MC、TC等词汇所迷惑——他们都是集成开发环境,而我们要学的是一门语言;

  5.不要放过任何一个看上去很简单的小编程问题——他们往往并不那么简单,或者可以引伸出很多知识点;

  6.会用Visual C++,并不说明你会C++;

  7.学class并不难,template、STL、generic programming也不过如此——难的是长期坚持实践和不遗余力的博览群书;

  8.如果不是天才的话,想学编程就不要想玩游戏——你以为你做到了,其实你的C++水平并没有和你通关的能力一起变高——其实可以时刻记住:学C++是为了编游戏的;

  9.看Visual C++的书,是学不了C++语言的;

  10.浮躁的人容易说:XX语言不行了,应该学YY;——是你自己不行了吧!?

  11.浮躁的人容易问:我到底该学什么;——别问,学就对了;

  12.浮躁的人容易问:XX有钱途吗;——建议你去抢银行;

  13.浮躁的人容易说:我要中文版!我英文不行!——不行?学呀!

  14.浮躁的人容易问:XX和YY哪个好;——告诉你吧,都好——只要你学就行;

  15.浮躁的人分两种:a)只观望而不学的人;b)只学而不坚持的人;

  16.把时髦的技术挂在嘴边,还不如把过时的技术记在心里;

  17.C++不仅仅是支持面向对象的程序设计语言;

  18.学习编程最好的方法之一就是阅读源代码;

  19.在任何时刻都不要认为自己手中的书已经足够了;

  20.请阅读《The Standard C++ Bible》(中文版:标准C++宝典),掌握C++标准;

  21.看得懂的书,请仔细看;看不懂的书,请硬着头皮看;

  22.别指望看第一遍书就能记住和掌握什么——请看第二遍、第三遍;

  23.请看《Effective C++》和《More Effective C++》以及《Exceptional C++》;

  24.不要停留在集成开发环境的摇篮上,要学会控制集成开发环境,还要学会用命令行方式处理程序;

  25.和别人一起讨论有意义的C++知识点,而不是争吵XX行不行或者YY与ZZ哪个好;

  26.请看《程序设计实践》,并严格的按照其要求去做;

  27.不要因为C和C++中有一些语法和关键字看上去相同,就认为它们的意义和作用完全一样;

  28.C++绝不是所谓的C的“扩充”——如果C++一开始就起名叫Z语言,你一定不会把C和Z语言联系得那么紧密;

  29.请不要认为学过XX语言再改学C++会有什么问题——你只不过又在学一门全新的语言而已;

  30.读完了《Inside The C++ Object Model》以后再来认定自己是不是已经学会了C++;

  31.学习编程的秘诀是:编程,编程,再编程;

  32.请留意下列书籍:《C++面向对象高效编程(C++ Effective Object-Oriented Software Construction)》《面向对象软件构造(Object-Oriented Software Construction)》《设计模式(Design Patterns)》《The Art of Computer Programming》;

  33.记住:面向对象技术不只是C++专有的;

  34.请把书上的程序例子亲手输入到电脑上实践,即使配套光盘中有源代码;

  35.把在书中看到的有意义的例子扩充;

  36.请重视C++中的异常处理技术,并将其切实的运用到自己的程序中;

  37.经常回顾自己以前写过的程序,并尝试重写,把自己学到的新知识运用进去;

  38.不要漏掉书中任何一个练习题——请全部做完并记录下解题思路;

  39.C++语言和C++的集成开发环境要同时学习和掌握;

  40.既然决定了学C++,就请坚持学下去,因为学习程序设计语言的目的是掌握程序设计技术,而程序设计技术是跨语言的;

  41.就让C++语言的各种平台和开发环境去激烈的竞争吧,我们要以学习C++语言本身为主;

  42.当你写C++程序写到一半却发现自己用的方法很拙劣时,请不要马上停手;请尽快将余下的部分粗略的完成以保证这个设计的完整性,然后分析自己的错误并重新设计和编写(参见43);

  43.别心急,设计C++的class确实不容易;自己程序中的class和自己的class设计水平是在不断的编程实践中完善和发展的;

  44.决不要因为程序“很小”就不遵循某些你不熟练的规则——好习惯是培养出来的,而不是一次记住的;

  45.每学到一个C++难点的时候,尝试着对别人讲解这个知识点并让他理解——你能讲清楚才说明你真的理解了;

  46.记录下在和别人交流时发现的自己忽视或不理解的知识点;

  47.请不断的对自己写的程序提出更高的要求,哪怕你的程序版本号会变成Version 100.XX;

  48.保存好你写过的所有的程序——那是你最好的积累之一;

  49.请不要做浮躁的人;

  50.请热爱C++! 
 

 数组合并

#include "stdafx.h"
#include "iostream.h"
#define max 100

typedef struct list
{
 int a[max];
 int length;
}list;

void chushihua(list &l)
{
 l.length=0;

}

void fuzhi(list &l)
{
 int i=0;
   cout<<"请输入"<<endl;
 while(1)
 {
  cin>>l.a[i];
  if(l.a[i]<0)
   break;
  else{l.length++;i++;} 
 }
}

void shuchu(list &l)
{
 int i=0;
 for(i=0;i<l.length;i++)
  cout<<l.a[i]<<"  ";
 cout<<endl;
}

void hebin(list &la,list &lb,list &lc)
{
 int la_len=la.length;
 int lb_len=lb.length;
 int i=0,j=0,k=0;
 cout<<la_len<<endl<<lb_len<<endl;
 while(i<la_len&&j<lb_len)
 {
  if(la.a[i]<=lb.a[j])
  {
   lc.a[k]=la.a[i];
   i++;
   k++;
   lc.length++;
  }
  else
  {
   lc.a[k]=lb.a[j];
   k++;
   j++;
   lc.length++;
  }
 }
 while(i<la_len)
 {
  lc.a[k]=la.a[i];
  i++;
  k++;
  lc.length++;
 }
 while(j<lb_len)
 {
  lc.a[k]=lb.a[j];
   k++;
   j++;
   lc.length++;
 }
 //for(k=0;k<lc.length;k++)
 // cout<<lc.a[k];
}

int main(int argc, char* argv[])
{
list la,lb,lc;
chushihua(lb);
chushihua(la);
chushihua(lc);
fuzhi(la);
fuzhi(lb);
hebin(la,lb,lc);
shuchu(lc);
 return 0;
}

//在输入数组的时候,按从小到大输入,因为我没写排序函数,本人英语不好哈,不好意思啊。

 猴子选大王——链表的实现

//在N个猴子中,从任意个猴子开始数1,2,3,数到3的猴子被驱除,
//下一个继续依次数1,2,3,每次数3的猴子都被驱除,
//剩余最后一个猴子就是大王

#include "stdafx.h"
#include "iostream.h"
#include "stdio.h"
#include "malloc.h"

typedef struct lnode
{
 int a;
 lnode *next;
}lnode;

bool init(lnode *l,int n)
{
 lnode *p;
 int i;
 l=(lnode*)malloc(sizeof(lnode));
 l->next=NULL;
 for(i=1;i<=n;i++)
 {
  p=(lnode *)malloc(sizeof(lnode));
  cin>>p->a;
  p->next=l->next;
  l->next=p;
  
 }

 int r=1;
 lnode *q;
 p=l->next;
 while(n>1)
 {
  p=p->next;
  n--; 
 }
 p->next=l->next;
 p=l->next;
 q=l->next;
 q=q->next;
 while(p&&q)
 {
  if(r%2==0)
  {
   p->next=q->next;
   q=q->next;
  }
  p=p->next;
  q=q->next;
  r++;
  if(p==p->next)
  {
   cout<<"大王是"<<p->a<<endl;
   return 1;
  
  }
 
 }
 return true;
}

 

int main(int argc, char* argv[])
{
 lnode *l;
 int n;
 cin>>n;
 init(l,n);
 return 0;
}

 行列式求值

用了一个多小时,晚上实在有点不想睡觉,起来写DD

数学建模的老师叫我用MATLAB来写,可是我还用得不好,程序老出错

没办法啊,就先用C++来写,程序没错哈,有哪个朋友有更好的算法,记得告诉我哈。

我在这里谢了……

 

#include<iostream.h>
#define NUM 15
class juzhen
{
private:
    double J[NUM][NUM];
    int flag;
    int n;
    double x,ZH;
public:
    juzhen(int);
    ~juzhen();
    void input(void);
    void create(void);
    void output(void);
    void out(void);
};
juzhen::juzhen(int j)
{
    n=j;
    flag=0;
    x=0;
    ZH=1;
}
juzhen::~juzhen()
{}
void juzhen::input()
{
    cout<<"请输入你所要计算的行列式:"<<endl;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
        {
            cin>>J[i][j];
        }
}
void juzhen::create()
{
    for(int a=0;a<n-1;a++)
    {
        if(J[a][a]==0)
        {
            for(int i=a+1;i<n;i++)
            {
                if(J[i][a]!=0)
                {
                    for(int j=a;j<n;j++)
                    {
                         double temp=J[a][j];
                         J[a][j]=J[i][j];
                         J[i][j]=temp;
                    }
                    flag++;
                    break;
                }
            }
        }
        for(int i=a+1;i<n;i++)
        {
            if(J[i][a]!=0)
            {
                 x=(-1)*J[i][a]/J[a][a];
                 for(int j=a;j<n;j++)
                 {
                     J[i][j]=J[i][j]+x*J[a][j];
                 }
            }
        }
    }
}
void juzhen::output()
{

    cout<<"经转化后的上三角行列式如下:"<<endl;
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<n;j++)
        {
            cout<<J[i][j]<<" ";
        }
        cout<<endl;
    }
}
void juzhen::out()
{

    cout<<"原行列式的值为:";
     for(int k=0;k<n;k++)
     {
         ZH=ZH*J[k][k];
     }
     if(flag%2==0)
         cout<<ZH;
     if(flag%2!=0)
         cout<<(-1)*ZH;cout<<endl;
}
void main()
{
    int s;
    cout<<"请输入你要计算的行列式的阶数:";
    cin>>s;
    juzhen W(s);
    W.input();
    W.create();
    W.output();
    W.out();
}

 西南交通大学研究生入学考试最后一道数据结构题目…用两个堆栈表示一个队列

//用两个堆栈表示一个队列。完全原创哈,有更好算法的朋友请告诉我下哈,谢谢。
#include "iostream.h"
#include "malloc.h"

typedef struct Stack //定义堆栈
{
 int *base;
 int *top;
 int stacksize;
}Stack;

 

int InitStack(Stack &s)  //初始化堆栈
{
 s.base=(int *)malloc(100*sizeof(int));
 if(!s.base)
  return 0;
 s.top=s.base;
 s.stacksize=100;
 return 1;
}

int DestroyStack(Stack &s)  //销毁堆栈
{
 free (s.base);
 free (s.top);
 return 1;
}

void ClearStack(Stack &s)  //清除堆栈中的内容
{
 s.top=s.base;

}

int StackEmpty(Stack s)  //判断堆栈是否为空
{
 if(s.base==s.top)
  return 1;
 else return 0;

}

int StackLength(Stack s)  //堆栈的长度
{
 return (s.top-s.base);

}

int GetTop(Stack s,int &e)  //获取堆栈的数据
{
 if(s.top==s.base)
  return 0;
 e=*(s.top-1);
 return e;
}

int Push(Stack &s,int &e)  //进栈
{
 if(s.top-s.base>=s.stacksize)
 {
  s.base=(int *)realloc(s.base,(s.stacksize+10)*sizeof(int));
   if(!s.base)
    return 0;
  s.top=s.base+s.stacksize;
  s.stacksize+=10;
 }
 *s.top++=e;
 s.stacksize++;
 return 1;

}

int Pop(Stack &s,int &e)  //出栈
{
 if(s.top==s.base)
  return 0;
 e=*--s.top;
 --s.stacksize;
 return e;

}

typedef struct queue //定义队列
{
 Stack a;
 Stack b;

}Queue;

int InitQueue(Queue &q)  //初始化队列
{
 InitStack(q.a);
 InitStack(q.b);
 return 1;

}

int DestroyQueue(Queue &q)  //销毁队列
{
 DestroyStack(q.a);
 DestroyStack(q.b);
 if(DestroyStack(q.a)&&DestroyStack(q.b))
  return 1;

}

void ClearQueue(Queue &q)  //清除队列
{
 ClearStack(q.a);
 ClearStack(q.b);
}

int QueueEmpty(Queue q)
{
 if(StackEmpty(q.a)==1&&StackEmpty(q.b)==1)
  return 1;//返回1表示队列为空
 else return 0;

}

int QueueLength(Queue q)
{
 return ((q.a.top-q.a.base)+(q.b.top-q.b.base));

}

int GetQueueTop(Queue q,int &e)  //获取队列的数据
{
 if(QueueEmpty(q)==0)
  return GetTop(q.b,e);
 else return 0;

}

int PushQueue(Queue &q,int &e)  //进队
{
 Push(q.a,e);
 q.a.stacksize++;
 if(Push(q.a,e))
  return 1;
 else return 0;

}

int PopQueue(Queue &q,int &temp)  //出队
{
 int e;
 if(StackEmpty(q.b)==1)
 {
  if(StackEmpty(q.a)==1)
   return 0;
  else
   while(StackEmpty(q.a)==0)
   {
    q.a.top--;
    *q.b.top=*q.a.top;
    q.b.top++; 
   }
 }
 temp=Pop(q.b,e);
 cout<<temp;
 q.b.stacksize--;
 if(Pop(q.b,e))
  return 1;
 else return 0;

}
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//主函数部分
int main(int argc, char* argv[])
{
 //……………………测试堆栈,与题无关………………………………
/*
 Stack s_a,s_b;
 int w=10;
 int r;
 InitStack(s_a);
 InitStack(s_b);
 Push(s_a,w);
 Pop(s_a,r);
 cout<<r<<endl;
 if(StackEmpty(s_a)==1)
  cout<<"堆栈为空。"<<endl;
  else cout<<"堆栈为空。"<<endl;
*/
 //……………………………………………………………………………
 //…………………………队列的实现部分………………………………
 Queue q_a;
 int e[7]={1,2,3,6,4,77,1};
 int b[7]={0};
 InitQueue(q_a);
 cout<<"进队顺序为:";
 if(QueueEmpty(q_a)==1)
 {
  for(int i=1;i<=7;i++)
  {
   PushQueue(q_a,e[i-1]);
   cout<<e[i-1]<<" ";
  }
 }
 cout<<endl;
 cout<<"出队顺序为:";
 for(int i=1;i<=7;i++)
 {
  PopQueue(q_a,b[i]);
  cout<<" ";

 }cout<<endl;
 return 0;
}

 

 二叉树的实现和遍历

#include <stdio.h>
#include <malloc.h>
//定义二叉树
typedef struct bitnode
{
    int data;
    struct bitnode *lchild,*rchild;
}bitnode,*bitree;
//创建二叉树利用先序创建
void createbitree(bitree *T)
{
    int dat;
    printf("请输入节点数据:");
    scanf("%d",&dat);
    if(dat==0) (*T) = NULL;
    else
    {
        (*T) = (bitree)malloc(sizeof(bitnode));
        (*T)->data=dat;     
        createbitree(&((*T)->lchild));     
        createbitree(&((*T)->rchild));
    }
}
//二叉树的先序遍历递归算法
void postorder10(bitree T)
{
    if (T != NULL)
    {
       printf("%d/t",T->data);
       postorder10(T->lchild);
       postorder10(T->rchild);

     }

}

//二叉树的中序遍历递归算法
void postorder20(bitree T)
{
    if (T != NULL)
    {
      postorder20(T->lchild);
       printf("%d/t",T->data);
       postorder20(T->rchild);
    }

}

//二叉树的中序遍历非递归算法
void postorder21(bitree t)
   {
    bitree s[100];
     int top=0;
     while (t!=NULL || top!=0)
      {
         while (t!=NULL)
         {
             s[++top]=t;   t=t->lchild ;
         }
           if (top!=0)
           {
            t=s[top--];  printf("%d/t",t->data);  t=t->rchild;
           }
      }
   }
//二叉树的后序遍历递归算法
void postorder30(bitree T)
{
    if (T != NULL)
    {
       postorder30(T->lchild);
       postorder30(T->rchild);
       printf("%d/t",T->data);
    }

}

//在二叉树t中查找值为x的结点
void locate(bitree t, int x)
 {
   bitree p;
   p=t;
   if (t == NULL)
    printf("0/n");
   else if( t->data == x)
     printf("%d/n",p->data);
   else
   {
      p=t->lchild;
      if (p)
        locate(t->lchild, x);
      else
       locate(t->rchild, x);
   }
}
//以二叉链表作存储结构,试编写求二叉树深度的算法
int BinTreeDetth(bitree T)
{
    int l,r;
    if(T==NULL)return 0;
   else
   {
       l=BinTreeDetth(T->lchild);
           r=BinTreeDetth(T->rchild);
           return((l>r?l:r)+1);
   }
}
//以二叉链表作为存储结构,试编写求二叉树中叶子数的算法
int LeafCount1(bitree T)  
{
    int i,j;
   if(!T) return 0;                     //空树没有叶子
  else if(T->lchild==NULL&&T->rchild==NULL)
  {
      return 1; //叶子结点
  }
 
  else
  {
      i=LeafCount1(T->lchild);
      j=LeafCount1(T->rchild);
          return (i+j);
  }
   //左子树叶子数加上右子树叶子数
}

void main()
{
   bitree T;int n,m;
   createbitree(&T);
   printf("Create Success!/n/n");
  while(1)
  {
    printf("请输入你要执行的操作:/n");
    printf("0------------------------结束此次操作/n");
    printf("1----------------------------先序遍历/n");
    printf("2----------------------------中序遍历/n");
    printf("3----------------------------后序遍历/n");
    printf("4----------------------查找你要的结点/n");
    printf("5---------------求此二叉排序树的深度/n");
    printf("6---------求此二叉排序树的叶子结点数/n");
    scanf("%d",&n);
    switch(n)
    {
     case 0:
           return;      
     case 1:
           printf("先序遍历为:/n");
           postorder10(T);
           printf("/n");
           break;
     case 2:
           printf("中序遍历为:/n"); 
          printf("递归:/n");
           postorder20(T);
           printf("/n");
           printf("非递归:/n");
           postorder21(T);
           printf("/n");
           break;
     case 3:
           printf("后序遍历为:/n"); 
           postorder30(T);
           printf("/n");
           break;
     case 4:
           printf("请输入你要查找的结点:/n");
           scanf("%d",&m);
           printf("你要查找的结点为: /n");
           locate(T,m);
           break;
     case 5:
           printf("树的深度为:/n");
           printf("%d/n",BinTreeDetth(T));
           break;
     case 6:
           printf("此树的叶子结点数为:/n");
           printf("%d/n",LeafCount1(T));
           break;
    }
  }
}

 Tc2.0 编写俄罗斯方块游戏

Tc2.0 编写俄罗斯方块游戏

很多编程爱好者都编写过俄罗斯方块的游戏程序。很久以前,我用Tc2.0也做过一个;最近有好些朋友看见我以前的俄罗斯方块的程序后,
问我是怎么做的。我一直想把这个程序的整个过程写一份详细的东西,与各位编程爱好者分享,一直没空。正好现在放假了,而且离回家还有几天。于是我就把这个程序重新写了一遍,尽量使程序的结构比较清晰好懂一些。同时写了下面的这份东西。

  俄罗斯方块游戏的程序中用到了一些方法。为了比较容易理解这些方法,我在讲述的同时写了些专门针对这些方法的示例程序。这些示例程序力求短小,目的是用最小的代码能够清楚的示例所用的方法。这些示例程序都经过tc2.0测试。最后还附了完整的俄罗斯方块游戏的源代码,和最终的可执行程序。如果你看了这份东东,有什么意见和想法,请发电子邮件告诉我。我将会继续更新这分东东,最新的版本可以在我的个人主页上下载。

  下面的问题是有关俄罗斯方块程序的,其中有些是朋友问我的,有些是我认为可能会被问到的。我尽量按问题从易到难排列这些问题。 关于俄罗斯方块程序的一些问题:
******************************************************

Tc2.0中怎么样设置图形显示?
Tc2.0中常用图形函数的用法?
怎样获取鍵盘输入?
怎样控制方块的移动?
怎样控制时间间隔(用于游戏中控制形状的下落)?
游戏中的各种形状及整个游戏空间怎么用数据表示?
游戏中怎么判断左右及向下移动的可能性?
游戏中怎么判断某一形状旋转的可能性?
按向下方向键时加速某一形状下落速度的处理?
怎么判断某一形状已经到底?
怎么判断某一已经被填满?
怎么消去已经被填满的一行?
怎么消去某一形状落到底后能够消去的所有的行?(如长条最多可以消去四行)
怎样修改游戏板的状态?
怎样统计分数?
怎样处理升级后的加速问题?
怎样判断游戏结束?
关于计分板设计的问题。
关于“下一个”形状取法的问题。
剩下的问题。

******************************************************
新的问题:
 我想有一个最高记录的显示,应该怎么做呀?
 我想实现一个进度存储功能,应该怎么做呀?

 

Tc2.0中怎么样设置图形显示?

  Tc2.0中有两种显示模式,一种是我们所熟知的字符模式,另一种是图形模式。在字符模式下只能显式字符,如ASCII字符。一般是显示25
行,每行80个字符。程序缺省的是字符模式。在字符模式下不能显式图形和进行绘图操作。要想进行图形显示和绘图操作,必须切换到图形模
式下。

  Tc2.0中用initgraph()函数可以切换到图形模式,用closegraph()可以从图形模式切换回字符模式。initgraph()和closegraph()都是图形
函数,使用图形函数必须包括头文件"graphics.h"。

  void far initgraph(int far *graphdriver,int far *graphmode,char far *pathtodriver);graphdriver是上涨指向图形驱动序号变量的指针;graphmode是在graphdriver选定后,指向图形显示模式序号变量的指针。pathtodriver表示存放图形驱动文件的路径。

  Tc2.0中有多种图形驱动,每种图形驱动下又有几种图形显示模式。在我的程序中图形驱动序号为VGA,图形显示模式序号为VGAHI。这是一种分辨率为640*480(从左到右坐标依次为0-639,从上到下坐标依次为0-479),能够显示16种颜色的图形模式。别的图形驱动序号和图形显示模式序号,可以从手册或联机帮助中找到。

  pathtodriver指示存放图形驱动文件的路径。图形驱动序号不同,图形驱动文件也不同。序号为VGA图形驱动对应"egavga.bgi"这个图形驱动文件。"egavga.bgi"一般在Tc目录下。

void far closegraph(void);
  没有参数,从图形模式直接返回字符模式。

initgraph()和closegraph()的常用用法如下:
int gdriver = VGA, gmode=VGAHI, errorcode;

/* initialize graphics mode */
initgraph(&gdriver, &gmode, "e://tc2");

/* read result of initialization */
errorcode = graphresult();

if (errorcode != grOk) /* an error occurred */
{
printf("Graphics error: %s/n", grapherrormsg(errorcode));
printf("Press any key to halt:");
getch();
exit(1); /* return with error code */
}

/* return to text mode */
closegraph();

Tc2.0中常用图形函数的用法?

在这里讲几个游戏中用到的绘图用的图形函数:
setcolor();
line();
rectangle();
settextjustify();
outtextxy();
setfillstyle();
bar();

void far setcolor(int color);
  设置画线、画框和在图形模式下显示文字的当前颜色。这个函数将影响line()、rectangle()和outtextxy()函数绘图的颜色。
color可以取常的颜色常量:
BLACK ? 0
BLUE ? 1
GREEN ? 2
CYAN ? 3
RED ? 4
MAGENTA ? 5
BROWN ? 6
LIGHTGRAY ? 7
DARKGRAY ? 8
LIGHTBLUE ? 9
LIGHTGREEN ?10
LIGHTCYAN ?11
LIGHTRED ?12
LIGHTMAGENTA ?13
YELLOW ?14
WH99vE ?15

void far line(int x1,int y1,int x2,int y2);
用当前颜色从(x1,y1)画一条到(x2,y2)的线段。

void far rectangle(int left,int top,int right,int bottom);
用当前颜色画一个左上角为(left,top)、右下角为(right,bottom)的矩形框。

void far settextjustify(int horz,int vert);
设置图形模式下文字输出的对齐方式。主要影响outtextxy()函数。
horiz和vert可取如下枚举常量:
horiz ?LEFT_TEXT ? 0 ?Left-justify text
?CENTER_TEXT ? 1 ?Center text
?RIGHT_TEXT ? 2 ?Right-justify text
vert ?BOTTOM_TEXT ? 0 ?Justify from bottom
?CENTER_TEXT ? 1 ?Center text
?TOP_TEXT ? 2 ?Justify from top

void far outtextxy(int x,int y,char * textstring);
在(x,y)处用当前字体(缺省的字体是DEFAULT_FONT)显示字符串textstring,字符串的对齐方式由settextjustify()指定。

void far setfillstyle(int pattern,int color);
设置图形的填充模式和填充颜色,主要影响bar()等函数。
pattern一般取枚举常量值SOLID_FILL,color的取值与setcolor(int color)中color的取值范围相同。

  介绍完了前面两个问题,现在来写一个程序。这个程序演示前了面所介绍的几个图形函数。
程序prog1.c

怎样获取鍵盘输入?

  在Tc2.0中有一个处理键盘输入的函数bioskey();
int bioskey(int cmd);
  当cmd为1时,bioskey()检测是否有键按下。没有键按下时返回0;有键按下时返回按键码(任何按键码都不为0),但此时并不将检测到的按
键码从键盘缓冲队列中清除。
  当cmd为0时,bioskey()返回键盘缓冲队列中的按键码,并将此按键码从键盘缓冲队列中清除。如果键盘缓冲队列为空,则一直等到有键按
下,才将得到的按键码返回。

  Escape键的按键码为0x11b,下面的小程序可以获取按键的按键码。

for (;;)
{
key=bioskey(0); /* wait for a keystroke */
printf("0x%x/n",key);
if (key==0x11b) break; /* Escape */
}

常用按键的按键码如下:

#define VK_LEFT 0x4b00
#define VK_RIGHT 0x4d00
#define VK_DOWN 0x5000
#define VK_UP 0x4800
#define VK_HOME 0x4700
#define VK_END 0x4f00
#define VK_SPACE 0x3920
#define VK_ESC 0x011b
#define VK_ENTER 0x1c0d

  完整的程序请参见prog2.c、prog3.c。
prog2.c获取按键的按键码,按Escape键退出程序。
prog3.c根据不同的按键进行不同的操作,按Escape键退出程序。

怎样控制方块的移动?
  方块移动的实现很简单,将方块原来的位置用背景色画一个同样大小的方块,将原来的方块涂去。然后在新的位置上重新绘制方块就可以
了。这样就实现了方块的移动。完整的程序请参见prog4.c。这个用方向键控制一个黄色的小方块在屏幕上上、下、左、右移动。这个程序用到了前面几个问题讲的内容,如果你有点忘了,还要回头看看哦。:)

怎样控制时间间隔(用于游戏中控制形状的下落)?
  解决这个问题要用到时钟中断。时钟中断大约每秒钟发生18.2次。截获正常的时钟中断后,在处理完正常的时钟中断后,将一个计时变量
加1。这样,每秒钟计时变量约增加18。需要控控制时间的时候,只需要看这个计时变量就行了。

  截获时钟中断要用到函数getvect()和setvect()。
两个函数的声明如下:
?void interrupt (*getvect(int interruptno))();
?void setvect(int interruptno, void interrupt (*isr) ( ));

  保留字interrupt指示函数是一个中断处理函数。在调用中断处理函数的时候,所有的寄存器将会被保存。中断处理函数的返回时的指令是iret,而不是一般函数用到的ret指令。

getvect()根据中断号interruptno获取中断号为interruptno的中断处理函数的入口地址。
setvect()将中断号为interruptno的中断处理函数的入口地址改为isr()函数的入口地址。即中断发生时,将调用isr()函数。

  在程序开始的时候截获时钟中断,并设置新的中断处理。在程序结束的时候,一定要记着恢复时钟中断哦,不然系统的计时功能会出问题
的。具体演示程序请参见prog5.c。由于中断处理大家可能用的不多,所以我把prog5.c这个程序完整地贴在下面,并加上详细的解释。

/* prog5.c */
This is an interrupt service routine. You can NOT compile this
program with Test Stack Overflow turned on and get an executable
file which will operate correctly. */

/* 这个程序每隔1秒钟输出一个整数,10秒钟后结束程序。
按escape键提前退出程序 。*/

#include
#include
#include

/* Escape key */
#define VK_ESC 0x11b

#define TIMER 0x1c /* 时钟中断的中断号 */

/* 中断处理函数在C和C++中的表示略有不同。
如果定义了_cplusplus则表示在C++环境下,否则是在C环境下。 */

#ifdef __cplusplus
#define __CPPARGS ...
#else
#define __CPPARGS
#endif

int TimerCounter=0; /* 计时变量,每秒钟增加18。 */

/* 指向原来时钟中断处理过程入口的中断处理函数指针(句柄) */
void interrupt ( *oldhandler)(__CPPARGS);

/* 新的时钟中断处理函数 */
void interrupt newhandler(__CPPARGS)
{
/* increase the global counter */
TimerCounter++;

/* call the old routine */
oldhandler();
}

/* 设置新的时钟中断处理过程 */
void SetTimer(void interrupt (*IntProc)(__CPPARGS))
{
oldhandler=getvect(TIMER);
disable(); /* 设置新的时钟中断处理过程时,禁止所有中断 */
setvect(TIMER,IntProc);
enable(); /* 开启中断 */
}

/* 恢复原有的时钟中断处理过程 */
void KillTimer()
{
disable();
setvect(TIMER,oldhandler);
enable();
}

void main(void)
{
int key,time=0;

SetTimer(newhandler); /* 修改时钟中断 */

for (;;)
{
if (bioskey(1))
{
key=bioskey(0);
if (key==VK_ESC) /* 按escape键提前退出程序 */
{
printf("User cancel!/n");
break;
}
}
if (TimerCounter>18) /* 1秒钟处理一次 */
{
/* 恢复计时变量 */
TimerCounter=0;
time++;
printf("%d/n",time);
if (time==10) /* 10秒钟后结束程序 */
{
printf("Program terminated normally!/n");
break;
}
}
}
KillTimer(); /* 恢复时钟中断 */

}

游戏中的各种形状及整个游戏空间怎么用数据表示?

以后我提到的形状都是指下面七种形之一及它们旋转后的变形体。

□□□□ □□□□ □□□□ □□□□
□■□□ □■■□ □□□□ □□□□
□■□□ □■□□ □■□□ □■■□
□■■□ □■□□ ■■■□ ■■□□

□□□□ □■□□ □□□□
□□□□ □■□□ □□□□
■■□□ □■□□ □■■□
□■■□ □■□□ □■■□

我定义了一个结构来表示形状。
struct shape
{
int xy[8];
int color;
int next;
}
-1 0 1 2
-3□□□□
-2□□□□
-1□□□□
0□■□□

  所有的各种形状都可以放在4x4的格子里。假定第二列,第四行的格子坐标为(0,0)(如上图中黑块所示),则每个形状的四个方块都可以用4
个数对来表示。坐标x从左向右依次增加,y从上到下依次增加。表示的时候,组成该形状的四个方块从左到右,从上到下(不一定非要按这个顺
序)。如上面七种形状的第一个用数对来表示就是(-2,0)、(-1,0)、(0,0)、(1,0)。结构shape中的xy就是用来表示这4个数对的。为了简化程序,用一维数组xy[8]来表示。xy[0]、xy[1]表示第一个数对,xy[2]、xy[3]表示第二个数对,依次类推。
  shape中的color表示形状的颜色,不同的形状有不同的颜色。七种形状及它们旋转后的变形体一共有19种形状,用一个全局数组表示。假定旋转的方向是逆时针方向(顺时针方向道理一样)。shape中的next就表示当前形状逆时针旋转后的下一个形状的序号。例如:第一种形状及其旋
转变形的形状用结构表示如下。

□□□□ □□□□ □□□□ □□□□
□■□□ □□□□ □■■□ □□□□
□■□□ □□■□ □□■□ ■■■□
□■■□ ■■■□ □□■□ ■□□□

struct shape shapes[19]=
{
/*{x1,y1,x2,y2,x3,y3,x4,y4, color, next}*/
{ 0,-2, 0,-1, 0, 0, 1, 0, CYAN, 1}, /* */
{-1, 0, 0, 0, 1,-1, 1, 0, CYAN, 2}, /* # */
{ 0,-2, 1,-2, 1,-1, 1, 0, CYAN, 3}, /* # */
{-1,-1,-1, 0, 0,-1, 1,-1, CYAN, 0}, /* ## */

……

}

  游戏空间指的是整个游戏主要的界面(呵呵,这个定义我实在想不出更准确的,还请哪位大虾指点)。实际上是一个宽10格子、高20格子的
游戏板。用一个全局数组board[12][22]表示。表示的时候:board[x][y]为1时表示游戏板上(x,y)这个位置上已经有方块占着了,board[x][y]
为0表示游戏板上这位置还空着。为了便于判断形状的移动是否到边、到底,初始的时候在游戏板的两边各加一列,在游戏板的下面加一行,全
部填上1,表示不能移出界。即board[0][y],board[11][y](其中y从0到21)初始都为1,board[x][21](其中x从1到10)初始都为1。
1 2 3 4 5 6 7 8 910
1□□□□□□□□□□
2□□□□□□□□□□
3□□□□□□□□□□
4□□□□□□□□□□
5□□□□□□□□□□
6□□□□□□□□□□
7□□□□□□□□□□
8□□□□□□□□□□
9□□□□□□□□□□
10□□□□□□□□□□
11□□□□□□□□□□
12□□□□□□□□□□
13□□□□□□□□□□
14□□□□□□□□□□
15□□□□□□□□□□
16□□□□□□□□□□
17□□□□□□□□□□
18□□□□□□□□□□
19□□□□□□□□□□
20□□□□□□□□□□

  prog6.c演示了用结构表示各种形状的方法。虽然程序稍长一些,但并不是特别复杂。其中游戏板初始化部分并没有真正用到,但是后面的程
序会用到的。其中SIZE定义为16,这样将整个屏幕的坐标系由原来的640×480转换成40×30(640/16=40,480/16=30)。游戏中所有的坐标都是基于40×30的坐标系的,这样有助于简化程序。坐标的转换在程序中由DrawBlock(int x,int y)来体现。

  新的坐标系如下图所示:
-8-7-6-5-4-3-2-1 0 1 2 3 4 5 6 7 8 910111213141516171819202122232425262728293031
-4□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
-3□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
-2□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
-1□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
0□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
1□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
2□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
3□□□□□□□□□■■■■■■■■■■□□□■■■■□□□□□□□□□□□□□□
4□□□□□□□□□■■■■■■■■■■□□□■■■■□□□□□□□□□□□□□□
5□□□□□□□□□■■■■■■■■■■□□□■■■■□□□□□□□□□□□□□□
6□□□□□□□□□■■■■■■■■■■□□□■■■■□□□□□□□□□□□□□□
7□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
8□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
9□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
10□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
11□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
12□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
13□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
14□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
15□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
16□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
17□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
18□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
19□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
20□□□□□□□□□■■■■■■■■■■□□□□□□□□□□□□□□□□□□□□□
21□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
22□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
23□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
24□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
25□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□
26□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□

  新坐标中最主要的是就是上面两块黑色的部分。左边那块大的就是游戏板(横坐标从1到10,纵坐标从1到20),右边那块小的就是显示“下一个”形状的部分(横坐标从14到17,纵坐标从3到6)。这个新的坐标系是整个游戏的基础,后面所有的移动、变形等的计算都是基于这个坐标系的。

游戏中怎么判断左右及向下移动的可能性?

  看懂了前面的各种形状和游戏板等的表示,接下来的东西就都好办多了。先来看一下某个形状如何显示在游戏板当中。假设要在游戏板中
显示第一个形状。第一个形状在结构中的表示如下:

struct shape shapes[19]=
{
/*{x1,y1,x2,y2,x3,y3,x4,y4, color, next}*/
{ 0,-2, 0,-1, 0, 0, 1, 0, CYAN, 1},

……

}

  那么这个组成形状四个方块的坐标表示为(0,-2)、(0,-1)、(0,0)和(1,0)。这实际上是相对坐标。假形状的实际坐标指的是4x4方块中的第
二列、第三行的方块的位置,设这个位置为(x,y)。那么组成这个形状的四个小方块的实际坐标(以第一个形状为例)就是(x+0,y-2)、(x+0,y-1)、(x+0,y+0)和(x+1,y+0)。由于所有的形状都可以在4x4的方块阵列中表示,这样就找到了一种统一的方法来表示所有的形状了。

-1 0 1 2
-3□□□□ 相对坐标
-2□■□□
-1□■□□ 组成第一种形状的四个方块的相对坐标为(0,-2)、(0,-1)、(0,0)和(1,0)。
0□■■□

让我们看看形状是如何显示在游戏板中的(以第一个形状为例)。

1 2 3 4 5 6 7 8 910
1□■□□□□□□□□ 形状的坐标为(2,3)。组成形状的四个方块的坐标由形状的
2□■□□□□□□□□ 坐标加上这四个小方块各自的相对坐标得出。它们分别是:
3□■■□□□□□□□ (2+0,3-2)、(2+0,3-1)、(2+0,3-0)和(2+1,3-0)。即:
4□□□□□□□□□□ (2,1)、(2,2)、(2,3)和(3,3)。如左图所示。
5□□□□□□□□□□
6□□□□□□□□□□
7■□□□□□□□□□ 形状的坐标为(1,9)。组成形状的四个方块的坐标分别是:
8■□□□□□□□□□ (1+0,9-2)、(1+0,9-1)、(1+0,9-0)和(1+1,9-0)。即:
9■■□□□□□□□□ (1,7)、(1,8)、(1,9)和(2,9)。如左图所示。
10□□□□□□□□□□
11□□□□□□□□□□
12□□□□□□□□□□
13□□□□□□□□□□
14□□□□□□□□□□
15□□□□□□□□□□
16□□□□□□□□□□
17□□□□□□□□□□
18□□□□□□□□■□ 形状的坐标为(9,20)。组成形状的四个方块的坐标分别是:
19□□□□□□□□■□ (9+0,20-2)、(9+0,20-1)、(9+0,20-0)和(9+1,20-0)。即:
20□□□□□□□□■■ (9,18)、(9,19)、(9,20)和(10,20)。如左图所示。

  从现在起,我不再举别的示例程序了。从现在开始所有的示例代码均来自于我写的"Russia.c"。为了记录游戏板的状态,用了一个全局数组board[12][22]。board[x][y](其中x从0到11,y从1到21)等于1表示(x,y)这个位置已经被填充了,组成形状的四个方块的坐标都不能为(x,y),否则将发生冲突。board[x][y](其中x从1到10,y从1到20)等于表示(x,y)这个位置还没有被填充。

  游戏板初始化时,给board[0][y],board[11][y](其中y从1到21)都赋为1,给board[x][21](其中x从1到10)都赋为1。这相当于一开始就给游戏板左右和下方加了个“边”。所有的形状都不能够移入这个“边”

抱歉!评论已关闭.