一、树的数据结构
//使用数组+下标的方式实现二叉树。
const int root=1;
void newtree()
{
left[root]=right[root]=0;
have_value[root]=false;
cnt=root;
}
int newnode()
{
int u=++cnt;
left[u]=right[u]=0;
have_value[u]=false;
return u;
}
//使用Node
struct Node
{
bool have_value;
int v;
Node *left,*right;
Node():have_value(false),left(NULL),right(NULL){}
};
bool failed;
Node* root;
char s[maxn];
//树节点的数据结构
//增加节点
Node* newnode()
{
return new Node();
}
//构建树
void addnode(int v,char* s)
{
int n = strlen(s);
Node* u = root;
for(int i=0;i<n;i++)
{
if(s[i]=='L')
{
if(u->left==NULL) u->left = newnode();
u=u->left;
}
else if(s[i]=='R')
{
if(u->right==NULL) u->right = newnode();
u=u->right;
}
}
if(u->have_value) failed=true;
u->v=v;
u->have_value=true;
}
实际上很多时候,我们直接使用left和right数组直接时使用。
const int root=0;left[root]和right[root]进行赋值,这样使用的不是动态数组,所以存储开销要计算好。因为很多空余是没有存储的。
二、树的BFS和DFS
在进行BFS的时候一般使用queue进行辅助遍历。
bool bfs(vector<int> &ans)
{
queue<Node*> q;
ans.clear();
q.push(root);
while(!q.empty())
{
Node* u=q.front();q.pop();
if(!u->have_value) return false;
ans.push_back(u->v);
if(u->left!=NULL) q.push(u->left);
if(u->right!=NULL)q.push(u->right);
}
return true;
}
使用DFS的时候,根据根的位置不同分为不同的遍历方式。总的而言,DFS都是递归遍历形式。
void postorder(int root)
{
// cout<<value; 先序遍历
if(lch[root]!=-1) postorder(lch[root]);
// cout<<value; 中序遍历
if(rch[root]!=-1) postorder(rch[root]);
//cout<<value; 后序遍历
}
三、 图的数据结构
图的数据结构一般采用邻居矩阵的形式,只有特别大的才考虑邻接表的形式进行存储。
四、图的BFS和DFS
采用dfs进行递归遍历的时候,一般配有visit数组来表示是否访问的点已经被访问。
void dfs(int r,int c,int id)
{
if(r<0||r>=m||c<0||c>=n) return;
//行和列越界判断
if(idx[r][c]>0||pic[r][c]!='@') return;
// idx[r][c]>0 表示已经被遍历过。
// 节约时间,快速返回。
idx[r][c]=id;
for(int dr=-1;dr<=1;dr++)
//dc和dr表示可以朝上下左右移动
for(int dc=-1;dc<=1;dc++)
if(dr!=0||dc!=0) dfs(r+dr,c+dc,id);
//dr和dc不能同时为0,如果同时为0,则原地不动。
}
采用bfs进行遍历的时候,同样也要使用队列进行辅助。采用循环判断队列是否为空的方式进行。
void solve()
{
queue<Node> q;
memset(d,-1,sizeof(d));
Node u(r1,c1,dir);//起点
d[u.r][u.c][u.dir]=0;
//初始状态到(r,c,dir)的最短路径
q.push(u);//然后将u压入栈内
while(!q.empty())//层次遍历是否结束
{
Node u = q.front();
q.pop();
if(u.r==r2 && u.c==c2)//表示如果u已经到达终点
{
printf_ans(u);//输出
return;
}
for(int i=0;i<3;i++)//3个方向
{
Node v = walk(u,i);
if(has_edge[u.r][u.c][u.dir][i]&&d[v.r][v.c][v.dir]<0)
//has_edge表示这种前进方式是否能够进入。d[v.r][v.c][v.dir]表示还没有到达这个点.
{
d[v.r][v.c][v.dir]=d[u.r][u.c][u.dir]+1;
p[v.r][v.c][v.dir]=u;
q.push(v);
}
}
}
printf(" No Solution Possible\n");
}
五、拓扑排序
#include<cstdio>
#include<cstring>
const int maxn=100+5;
//c数组,0表示从未访问过,1表示已经访问并递归过它的子孙。
//-1表示正在访问。
int c[maxn];
int topo[maxn],t,n;
int G[maxn][maxn];
bool dfs(int u)
{
c[u]=-1;
for(int v=1;v<=n;v++)
{
if(G[u][v])
//采用邻接矩阵存储图,表示u有指向v的边,表示u完成后v才能完成。
{
if(c[v]<0) return false;//判断是否有环的存在
else if (!c[v]&&!dfs(v)) return false;
//如果v已经被访问过,则退出。
//如果没有访问,就进行深度遍历,进行访问。
}
}
c[u]=1;topo[--t]=u;
return true;
}
bool toposort()
{
t=n;
memset(c,0,sizeof(c));
for(int u=1;u<=n;u++)
{
if(!c[u])//没有进行访问的才进行访问
{
if(!dfs(u)) return false;
}
}
return true;
}
int main()
{
//freopen("datain.txt","r",stdin);
//freopen("dataout.txt","w",stdout);
int m;
while(scanf("%d%d",&n,&m)&&n)
{
memset(G,0,sizeof(G));
while(m--)
{
int i,j;
scanf("%d%d",&i,&j);
G[i][j]=1;
}
toposort();
for(int i=0;i<n;i++)
{
printf("%d",topo[i]);
if(i<n-1)
printf(" ");
}
printf("\n");
}
return 0;
}
六、欧拉回路
存在欧拉回路的情况是:最多只能两个点的入度不等于出度,而且一个点是入度比出度大1,另外一个点是出度比入度大1。前提条件是图必须是连通的。