文章目录
- 顺序表的操作
- 单链表的基本操作
- 顺序栈的基本操作
- 链栈的基本操作
- 队列的顺序表基本操作
- 队列的链式实现和基本操作
- 案例3.1 数制的转换
- 案例3.2:括号匹配的检验
- 图
- 2、设有向图G有n个点(用1,2,…,n表示),e条边,写一算法根据G的邻接表生成G的反向邻接表,要求算法时间复杂性为O(n+e)。【东南大学1996三(13分)1992六(18分)】【北京邮电大学2006五、3(10分)】
- 6.写出从图的邻接表表示转换成邻接矩阵表示的算法,用类 Pascal 语言(或C语言)写成过程形式。
- 7.试写出把图的邻接矩阵表示转换为邻接表表示的算法。
- 8.已知某有向图(n个结点)的邻接表,求该图各结点的入度数。【天津大学2001 五(10分)
- 9.设计一个算法,统计一个采用邻接矩阵存储,具有n个顶点的无向无权图所有顶点的度。【天津大学2005六(10分)】
- 12.已知无向图G=(V,E),给出求图G的连通分量个数的算法
- 14.已知无向图采用邻接表存储方式,试写出删除边(i, j)的算法。【东南大学1999三(10分)】北京邮电大学2006三(7分)】
- 15.试写一算法,判断以邻接表方式存储的有向图中是否存在由顶点V到顶点V的路径(ij)注意:算法中涉及的图的基本操作必须在存储结构上实现。【哈尔滨工业大学2001九 (12分)】
- 16.按图的广度优先搜索法写一算法判别以邻接矩阵存储的有向图中是否存在由顶点v到顶点V的路径(i≠j)。【中山大学1997五(10分)】
- 18.编写程序,判断一个用邻接表存储的有向图是否存在回路,并写出算法思想。【南京航空航天大学2006 8 (5分)】
- 树
- 中序遍历的非递归算法
- 复制二叉树
- 计算二叉树的深度
- 计算二叉树中结点个数
- 统计二叉树的叶结点个数
- 判别两棵树是否相等
- 交换二叉树每个结点左孩子和右孩子
- 双序遍历二叉树
- 计算二叉树的最大宽度
- 统计树中度为1的结点数目
- 二叉树的带权路径长度(WPL)是二叉树中所有叶结点的带权路径长度之和。设计算法求WPL
- 假设一个仅包含二元运算符的算术表达式以链表形式存储在二叉树BT中,写出计算该算术表达式值的算法
- 非递归后序遍历二叉树
- 试给出二叉树的自上而下、从右到左的层次遍历算法
- 设计一个非递归算法求二叉树的高度
- 试编写一个算法,判断给定的二叉树是否是二叉排序树
- 已知[深度](https://so.csdn.net/so/search?q=深度&spm=1001.2101.3001.7020)为h的二叉树采用顺序存储结构已存放于数组BT[1:2^h-1]中,请写一非递归算法产生该二叉树的二叉链表结构。设二叉链表中链结点的构造为(lchild,data,rchild),根结点所在链结点的指针由T给出。
- 在一棵二叉链表表示的二叉树中,root为根结点,p和q为二叉树中两个结点,编写程序,求距离它们最近的共同祖先,并写出算法思想
- 在二叉树中查找值为x的结点,试编写算法打印值为x的结点的所有祖先,假设值为x的结点不多于一个
- 已知二叉树采用二叉链表存储,设计算法以输出二叉树T中根结点到每个叶子结点的路径
- 线索二叉树
- 串
顺序表的操作
特别需要注意的地方
要考虑查询、删除、插入的位置合不合理
或者有没有超过数组最大长度
if(i<1||i>L.length+1)
return false;
if(L.length>=L.MAXSIZE)
return false;
可直接运行调试的代码
#include<iostream>
using namespace std;
#define InitSIZE 50
// 初始化表
typedef struct
{
int *data;
int length;
int MAXSIZE;
}SqList;
//初始化顺序表
bool InitList(SqList &L)
{
L.data = new int[InitSIZE];
if(!L.data) return false;
L.length=0;
L.MAXSIZE=InitSIZE;
return true;
}
int Length(SqList L)
{
return L.length;
}
//插入到第i个位置
bool ListInsert(SqList &L,int i,int e)
{
if(i<1||i>L.length+1)
return false;
if(L.length>=L.MAXSIZE)
return false;
for(int j=L.length;j>=i;j--)
{
L.data[j]=L.data[j-1];
}
L.data[i-1]=e;
L.length++;
return true;
}
//删除表L中第i个位置的元素
bool ListDelete(SqList &L,int i)
{
if(i<0||i>L.length)return false;
for(int j=i-1;j<L.length;j++)
{
L.data[j]=L.data[j+1];
}
L.length--;
return true;
}
void print(SqList L)
{
for(int i=0;i<L.length;i++)
{
cout<<L.data[i]<<" ";
}
cout<<endl;
}
int main()
{
int x;
cin>>x;
SqList L;
InitList(L);
ListInsert(L,1,x);
ListInsert(L,1,3);
print(L);
ListDelete(L,2);
print(L);
}
单链表的基本操作
#include<iostream>
using namespace std;
int a[5]={1,2,3,4,5};
typedef struct LNode
{
int data;
struct LNode *next;
}LNode,*LinkList;
//初始化单链表
bool InitList(LinkList &L)
{
L = new LNode;
L->next=NULL;
return true;
}
//前插法创建单链表
void CreateList_H(LinkList &L, int n)
{
int data;
for(int i=0;i<n;i++)
{
LinkList p = new LNode;
p->data=a[i];
p->next=L->next;
L->next=p;
}
}
//后插法创建单链表
void CreateList_R(LinkList &L,int n)
{
LinkList r = L;
for(int i=0;i<n;i++)
{
LinkList p = new LNode;
p->data = a[i];
p->next = NULL;
r->next = p;
r=p;
}
}
//在带头结点的单链表L中根据序号i获取元素的值,用e返回L中第i个数据元素的值
bool GetElem(LinkList L,int i, int &e)
{
int cnt=1;
LinkList p = L->next;
while(cnt!=i&&p)
{
p=p->next;
cnt++;
}
if(!p||i<=0)return false;
e = p->data;
cout<<e<<endl;
return true;
}
//查找值为e的地址
LNode *LocateElem(LinkList &L,int e)
{
LinkList p=L->next;
while(p&&p->data!=e)
{
p=p->next;
}
return p;
}
//在链表L中第i个位置插入值为e的结点
bool ListInsert(LinkList &L,int i,int e)
{
LinkList p=L;
int cnt=1;
while(cnt<i&&p)
{
p=p->next;
cnt++;
}
if(!p||i<=0)return false;
LinkList s = new LNode;
s->data=e;
s->next=p->next;
p->next=s;
return true;
}
//删除第i个位置上的元素
bool ListDelete(LinkList &L,int i)
{
LinkList p = L->next;
int cnt=1;
while(cnt<i-1&&p)
{
p=p->next;
cnt++;
}
if(!p->next||cnt>i-1) return false;
p->next=p->next->next;
return true;
}
void print(LinkList L)
{
LinkList p = L;
while(p->next)
{
p=p->next;
cout<<p->data<<" ";
}
cout<<endl;
}
int main()
{
LinkList L = new LNode;
int e;
InitList(L);
CreateList_R(L,5);
print(L);
GetElem(L,2,e);
ListDelete(L,3);
print(L);
ListInsert(L,2,1);
print(L);
}
顺序栈的基本操作
#include<iostream>
using namespace std;
#define MAXSIZE 100
int a[1001]={1,3,5,6,7};
//顺序栈结构
typedef struct
{
int *base; //栈底指针
int *top; //栈顶指针
int stackseize; //栈可用的最大容量
}SqStack;
//初始化顺序栈
bool InitStack(SqStack &S)
{
S.base = new int[MAXSIZE];
if(!S.base) return false; // 存储分配失败
S.top=S.base;
S.stackseize=MAXSIZE;
return true;
}
//入栈 插入元素e为新的栈顶元素
bool Push(SqStack &S,int e)
{
if(S.top-S.base==S.stackseize)
return false; //栈满返回错误
*S.top++=e;
return true;
}
//出栈,并将栈顶元素赋值给e
bool Pop(SqStack &S,int &e)
{
if(S.top==S.base) return false;
e=*--S.top; //需要理解一下 栈顶指针指向的元素实际已经出栈
return true;
}
//取栈顶元素
int GetTop(SqStack S)
{
if(S.top!=S.base)
return *(S.top-1);
}
int main()
{
SqStack S;
InitStack(S);
int input,output;
cout<<"请依次输入5个入栈元素:";
for(int i=0;i<5;i++)
{
cin>>input;
Push(S,input);
}
Pop(S,output);
cout<<"出栈:"<<output<<endl;
cout<<"取当前栈顶元素:"<<GetTop(S)<<endl;
cout<<"输出剩余栈顶元素:"<<endl;
while(Pop(S,output))
{
cout<<output<<" ";
}
return 0;
}
链栈的基本操作
#include<iostream>
using namespace std;
#define MAXSIZE 100
typedef struct StackNode
{
int data;
struct StackNode *next;
}StackNode,*LinkStack;
//链栈的初始化操作就是构造一个空栈,
//因为没必要设置头结点,所以直接将栈顶指针置空
bool InitStack(LinkStack &S)
{
S=NULL;
return true;
}
//入栈采用头插法
bool Push(LinkStack &S,int e)
{
LinkStack node = new StackNode;
node->data=e;
node->next=S;
S=node;
return true;
}
//出栈,并将栈顶元素赋值给e
bool Pop(LinkStack &S,int &e)
{
//栈空返回false
if(S==NULL)
{
cout<<"空栈!!";
return false;
}
e=S->data;
S=S->next;
return true;
}
//返回栈顶元素
int GetTop(LinkStack S)
{
if(S!=NULL)
return S->data;
}
int main()
{
LinkStack S = new StackNode;
int input,output;
InitStack(S);
cout<<"请输入5个入栈元素:";
for(int i=0;i<5;i++)
{
cin>>input;
Push(S,input);
}
cout<<"弹出栈顶元素:";
Pop(S,output);
cout<<output<<endl;
cout<<"查询栈顶元素:"<<GetTop(S)<<endl;
cout<<"输出剩余栈内元素:";
while(S)
{
Pop(S,output);
cout<<output<<" ";
}
cout<<endl;
cout<<"弹出栈顶元素:";
Pop(S,output);
}
队列的顺序表基本操作
#include<iostream>
using namespace std;
#define MAXSIZE 100
//队列的顺序存储结构
typedef struct
{
int *base;
int front;
int rear;
}SqQueue;
//初始化队列
bool InitQueue(SqQueue &Q)
{
Q.base = new int[MAXSIZE];
if(!Q.base) return false;
Q.front=Q.rear=0;
return true;
}
//求队列的长度
int QueueLength(SqQueue Q)
{
return (Q.rear-Q.front+MAXSIZE)%MAXSIZE;
}
//判断队列是否满
//将新元素插入队尾
//队尾指针+1
bool EnQueue(SqQueue &Q,int e)
{
if((Q.rear+1)%MAXSIZE==Q.front)
return false;
Q.base[Q.rear]=e;
Q.rear=(Q.rear+1)%MAXSIZE;
return true;
}
//判断队列是否为空
//保存队头元素
//队头指针加1
bool DeQueue(SqQueue &Q,int &e)
{
if(Q.rear==Q.front) return false;
e=Q.base[Q.front];
Q.front=(Q.front+1)%MAXSIZE;
return true;
}
int GetHead(SqQueue Q)
{
if(Q.front!=Q.rear)
return Q.base[Q.front];
}
int main()
{
SqQueue Q;
int a,b;
InitQueue(Q);
cout<<"请输入5个需要入队的元素:";
for(int i=0;i<5;i++)
{
cin>>a;
EnQueue(Q,a);
}
cout<<"出队:";
DeQueue(Q,b);
cout<<b<<endl;
cout<<"得到队头:"<<GetHead(Q)<<endl;
cout<<"剩余元素全部出队:";
while(Q.front!=Q.rear)
{
DeQueue(Q,b);
cout<<b<<" ";
}
}
队列的链式实现和基本操作
需要注意的是,链式队列的存储结构嵌套了两个结构
而且它是一个带头结点的链表
#include<iostream>
using namespace std;
#define MAXSIZE 100
//这里用struct QNode
//而前面不用,是因为这里要定义结构指针 struct QNode *next
typedef struct QNode
{
int data;
struct QNode *next;
}QNode,*QueuePtr;
typedef struct
{
QueuePtr front;
QueuePtr rear;
}LinkQueue;
//生成新节点作为头结点,队头和队尾指针指向此节点
//头结点的指针域置为空
bool InitQueue(LinkQueue &Q)
{
Q.front=Q.rear=new QNode;
Q.front->next=NULL;
return true;
}
//1、生成一个结点node,并装配结点
//2、将队尾指针的next指向这个结点
//3、修改队尾指针为node
bool EnQueue(LinkQueue &Q,int e)
{
QueuePtr node = new QNode;
node->data=e;
node->next=NULL;
Q.rear->next=node;
Q.rear=node;
return true;
}
//保存队头元素的空间,以备释放
//修改头结点的指针域,指向下一个结点
//判断出队元素是否为最后一个元素,若是,则将队尾指针重新赋值,指向头结点
//释放原队头元素的空间
bool DeQueue(LinkQueue &Q,int &e)
{
//队空,无法出队
if(Q.front==Q.rear) return true;
QueuePtr node = Q.front->next;
e=node->data;
Q.front->next=node->next;
//如果是最后一个元素被删除,队尾指针指向头结点
if(Q.rear==node) Q.rear=Q.front;
delete node;
return true;
}
int GetHead(LinkQueue Q)
{
if(Q.front!=Q.rear)
{
return Q.front->next->data;
}
}
int main()
{
LinkQueue Q;
InitQueue(Q);
int a,b;
cout<<"请输入要入队的5个元素:";
for(int i=0;i<5;i++)
{
cin>>a;
EnQueue(Q,a);
}
cout<<"出队:";
DeQueue(Q,b);
cout<<b<<endl;
cout<<"查询队头元素:"<<GetHead(Q)<<endl;
cout<<"输出剩余元素:";
while(Q.rear!=Q.front)
{
DeQueue(Q,b);
cout<<b<<" ";
}
}
案例3.1 数制的转换
问题:将一个十进制整数N转换为八进制数
主要算法
void conversion(int N)
{
SqStack S;
InitStack(S);
while(N)
{
Push(S,N%8);
N/=8;
}
//当栈非空时,循环输出
while(S.base!=S.top)
{
int a;
Pop(S,a);
cout<<a;
}
}
案例3.2:括号匹配的检验
//左括号压栈,右括号如果匹配则弹出栈顶,不匹配则结束循环,报错
bool Matching(SqStack S,string s)
{
int flag=1,x;
int index=0;
while(index!=s.size()&&flag)
{
print(S);
switch(s[index])
{
case '[':{
Push(S,s[index]);
break;
}
case '(':{
Push(S,s[index]);
break;
}
case ')':{
if(!StackEmpty(S)&&GetTop(S)=='(')
Pop(S,x);
else flag=0;
break;
}
case ']':{
if(!StackEmpty(S)&&GetTop(S)=='[')
Pop(S,x);
else flag=0;
break;
}
}
index++;
}
if(StackEmpty(S)&&flag) return true;
else return false;
}
int main()
{
string s;
SqStack S;
InitStack(S);
cin>>s;
cout<<s.size();
if(Matching(S,s))
{
cout<<"括号匹配成功"<<endl;
}
else cout<<"匹配失败!"<<endl;
}
图
1、(单独命题考生做)设无向图G有n个顶点,m条边。试编写用邻接表存储该图的算法。(设顶点值用1~n或0~n-1编号)【南京航空航天大学1996十二 (10分)】
①输入总顶点数和总边数
②建立顶点表
依次输入各个点的信息存入顶点表中
使每个表头结点的指针域都初始化为NULL
③创建邻接表
依次输入每条边依附的两个顶点
查找确定两个顶点的序号i和j,建立边结点
将此边结点分别插入到vi和vj对应的两个边链表的头部,利用头插法,每次都插入在表结点的后面
#define MVNum 100
typedef struct ArcNode
{
int adjvex;
struct ArcNode *nextarc;
int data;
}ArcNode;
typedef struct VNode
{
int data;
ArcNode *firstarc;
}VNode,AdjList[MVNum];
typedef struct
{
AdjList vexs;
int vexnum,arcnum;
}ALGragh;
void Create(ALGraph &G)
{
cin>>G.vexnum>>G.arcnum;
for(k=0;k<G.vexnum;k++)
{
cin>>G.vexs[k].data;
G.vexs[k].firstarc=NULL;
}
for(k=0;k<G.arcnum;k++)
{
cin>>v1>>v2;
i=LocateVex(G,v1) //找v1在图中的下标
j=LocateVex(G,v2);
p=new ArcNode;
p->adjvex=j;
p->nextarc=G.vexs[i].firstarc;
G.vexs[i].firstarc=p;
p1=new ArcNode;
p1->adjvex=i;
p1->nextarc=G.vexs[j].firstarc;
G.vexs[j].firstarc=p1;
}
}
2、设有向图G有n个点(用1,2,…,n表示),e条边,写一算法根据G的邻接表生成G的反向邻接表,要求算法时间复杂性为O(n+e)。【东南大学1996三(13分)1992六(18分)】【北京邮电大学2006五、3(10分)】
①初始化逆邻接表的顶点信息
②遍历出度表,把出度表的下标当做adjvex,出度表边结点的adjvex是入度的头。依次插入到入度表中
//将出度领接表改为入度邻接表
void reverse(ALGragh Gout,ALGraph &Gin)
{
/*将图的邻接表转化为逆邻接表*/
GIn.arcnum = GOut.arcnum; //初始化逆邻接表的边数目
GIn.vexnum = GOut.vexnum; //初始化逆邻接表的顶点数目
for (int i = 1; i <= GIn.vexnum; i++) {
GIn.vertices[i].data = GOut.vertices[i].data; // 初始化逆邻接表的顶点信息
GIn.vertices[i].first = NULL; // 初始化指向第一条依附该顶点的弧的指针
}
for(int i = 1; i <= GOut.vexnum; i++) {
ArcNode *p = GOut.vertices[i].first; // 取得指向第一条依附该顶点的弧的指针
ArcNode *s;
while(p != NULL) { // 遍历邻接表中第i个顶点所有邻接边
s = new ArcNode;
int temp = p -> adjvex;
s -> adjvex = i;
s -> next = GIn.vertices[temp].firstarc; //头插法将顶点i挂到GIn.vertices[temp]的边表中
GIn.vertices[temp].firstarc = s;
p = p -> next; // 继续往后遍历i所指向的顶点
}
}
}
6.写出从图的邻接表表示转换成邻接矩阵表示的算法,用类 Pascal 语言(或C语言)写成过程形式。
#define MVNnum 100
typedef struct ArcNode
{
int data;
int adjvex;
struct ArcNode* nextarc;
}ArcNode;
typedef struct VNode
{
int data;
ArcNode *firstarc;
}VNode,AdjList[MVNum];
typedef struct
{
AdjList vexs;
int vexnum,arcnum;
}ALGragh;
typedef struct
{
int vexs[MVNum];
int arcs[MVNum][MVNum];
int vexnum,arcnum;
}AMGraph;
void ALtoAM(AMGraph &M,ALGraph G)
{
M.vexnum=G.vexnum;
M.arcnum=G.arcnum;
for(k=0;k<G.vexnum;k++)
{
M.vexs[k]=G.vexs[k].data;
}
for(k=0;k<G.vexnum;k++)
{
p=new ArcNode;
p=G.vexs[K].firstarc;
while(p!=NULL)
{
p=p->nextarc;
i=Locate(G,k),j=Locate(G,p->adjvex);
M.arcs[i][j]=p->data;
}
}
}
7.试写出把图的邻接矩阵表示转换为邻接表表示的算法。
void AMtoAL(AMGragh M,ALGragh &G)
{
G.vexnum=M.vexnum;
G.arcnum=M.arcnum;
for(i=0;i<M.vexnum;i++)
{
for(j=0;j<M.vexnum;j++)
{
if(M.arcs[i][j]!=0)
{
p = new ArcNode;
p->adjvex=j;
p->next=G.vexs[i].firstarc;
G.vexs[i].firstarc=p;
}
}
}
}
8.已知某有向图(n个结点)的邻接表,求该图各结点的入度数。【天津大学2001 五(10分)
#define MVNum 100
typedef struct ArcNode
{
int adjvex;
struct ArcNode* nextarc;
int data;
}ArcNode;
typedef struct VNode
{
struct VNode* firstarc;
int data;
}VNode,AdjList[MVNum];
typedef struct
{
AdjList vexs;
int vexnum,arcnum;
}ALGragh;
int rudushu[MVNnum];
void Init()
{
for(i=0;i<MVNum;i++)
{
rudushu[i]=0;
}
}
void InGragh(ALGragh &G)
{
for(i=0;i<G.vexnum;i++)
{
p = new ArcNode;
p = G.vexs[i].firstarc;
while(p!=NULL)
{
if(p->adjvex=i)
rudushu[i]++;
p=p->next;
}
}
}
9.设计一个算法,统计一个采用邻接矩阵存储,具有n个顶点的无向无权图所有顶点的度。【天津大学2005六(10分)】
#define MVNum 100
typedef struct
{
int vexs[MVNum];
int arcs[MVNum][MVNum];
int vexnum,arcnum;
}AMGraph;
int ru[MVNum];
void Calcrudu(AMGragh &G)
{
for(i=0;i<vexnum;i++)
{
for(j=0;j<vexnum;j++)
{
if(G.arcs[i][j]!=0)
{
ru[i]++;
}
}
}
}
12.已知无向图G=(V,E),给出求图G的连通分量个数的算法
#define MVNum 100
typedef struct
{
int vexs[MVNum];
int arcs[MVNum];
int vexnum,arcnum;
}AMGragh;
void DFS_AM(AMGragh G,int v)
{
cout<<v;
vis[v]=true;
for(w=0;w<G.vexnum;w++)
if(G.arcs[v][w]!=0&&!vis[w])
DFS_AM(G,w);
}
int calc(AMGragh G,int count)
{
for(v=0;v<G.vexnum;v++)
vis[v]=false;
for(v=0;v<G.vexnum;v++)
if(!vis[v])
{
cnt++;
DFS_AM(G,V);
}
}
14.已知无向图采用邻接表存储方式,试写出删除边(i, j)的算法。【东南大学1999三(10分)】北京邮电大学2006三(7分)】
#define MVNum 100
typedef struct ArcNode
{
int data;
struct ArcNode *nextarc;
int adjvex;
}ArcNode;
typedef struct VNode
{
int data;
struct VNode* firstarc;
}VNode,AdjList[MVNum];
typedef struct
{
AdjList vexs;
int vexnum,arcnum;
}ALGragh;
void delete_AL(AlGragh &G,int i,int j)
{
p=new ArcNode;
p=G.vexs[i].firstarc;
while(p!=NULL&&p->next->adjvex!=j)
{
p=p->nextarc;
}
p->next=p->next->next;
}
15.试写一算法,判断以邻接表方式存储的有向图中是否存在由顶点V到顶点V的路径(ij)注意:算法中涉及的图的基本操作必须在存储结构上实现。【哈尔滨工业大学2001九 (12分)】
#define MVNum 100
typedef struct ArcNode
{
int data,adjvex;
struct ArcNode* nextarc;
}ArcNode;
typedef struct VNode
{
int data;
struct VNode* firstarc;
}VNode,AdjList[MVNum];
typedef struct
{
AdjList vexs;
int vexnum,arcnum;
}ALGragh;
//深度遍历a,b两点是否存在路径 ,haspath=1为有路径
void existPath(int a,int b,ALGragh G,int &haspath)
{
int m,n;
m=Locate(G,a);
n=Locate(G,b);
vis[m]=1;
p = new ArcNode;
p=G.vexs[m].firstarc;
if(m==n)
{
haspath=1;
}
while(p)
{
if(p->adjvex==b)
{
haspath=1;
break;
}
if(!vis[Locate(G,p->adjvex)])
existPath(p->adjvex,b,G);
p=p->nextarc;
}
}
16.按图的广度优先搜索法写一算法判别以邻接矩阵存储的有向图中是否存在由顶点v到顶点V的路径(i≠j)。【中山大学1997五(10分)】
#define MVNum 100
typedef struct
{
int vex[MVNum];
int arc[MVNum][MVNum];
int vexnum,arcnum;
}AMGragh;
void BFS(AMGragh G,int i,int j,int haspath)
{
Queue Q;
InitQueue(Q);
EnQueue(Q,i);
while(!QueueEmpty(Q)&&haspath=0)
{
DeQueue(Q,u);//队头元素出队并置为u
for(k=0;k<G.vexnum;k++)
{
if(arc[u][j]==1)
{
haspath=1;
break;
}
if(arc[u][k]==1&&!vis[k])
{
vis[k]=true;
EnQueue(Q,k);
}
}
}
}
18.编写程序,判断一个用邻接表存储的有向图是否存在回路,并写出算法思想。【南京航空航天大学2006 8 (5分)】
#define MVNum 100
typedef struct ArcNode
{
int data;
int adjvex;
struct ArcNode* nextarc;
}ArcNode;
typedef struct VNode
{
int data;
struct VNode* firstarc;
}VNode,AdjList[MVNum],
typedef struct
{
AdjList vexs;
int vexnum,arcnum;
}ALGragh;
void Cycle(ALGragh G,int v,bool &has)
{
p=new ArcNode;
p=G.vexs[v].firstarc;
while(p)
{
w=p->adjvex;
if(vis[w]==0)
Cycle(G,w,has);
else has=true;
p=p->nextarc;
}
}
树
中序遍历的非递归算法
void InOrder(Bitree T)
{
InitStack(S);p=T;
q=new BiTNode;
while(p||!StackEmpty(S))
{
if(p)
{
Push(S,p);
p=p->lchild;
}
else
{
Pop(S,q);
cout<<q->data;
p=q->rchild;
}
}
}
复制二叉树
void Copy(Bitree T,Bitree &NewT)
{
if(T==NULL)
{
NewT=NULL;
return ;
}
else
{
NewT=new BitNode;
NewT->data=T->data;
Copy(T->lchild,NewT->lchild);
Copy(T->rchild,NewT->rchild);
}
}
计算二叉树的深度
int Depth(Bitree T)
{
if(T==NULL)return 0;
else
{
m=Depth(T->lchild);
n=Depth(T->rchild);
return (m>n?m:n)+1;
}
}
计算二叉树中结点个数
int NodeCount(Bitree T)
{
if(T==NULL) return 0;
else return NodeCount(T->lchild)+NodeCount(T->rchild)+1;
}
统计二叉树的叶结点个数
int LeafNodeCount(Bitree T)
{
if(T==NULL)
return 0;
else if(T->lchild==NULL&&T->rchild==NULL)
return 1;
else return LeafNodeCount(T->lchild)+LeafNodeCount(T->rchild);
}
判别两棵树是否相等
bool compTree(BTree a, BTree b)
{
if(a == NULL && b == NULL)
return true;
if(a == NULL && b != NULL || a != NULL && b == NULL)
return false;
if(a->data == b->data)
{
if(compTree(a->lChild, b->lChild))
return compTree(a->rChild, b->rChild))
else if(compTree(a->lChild, b->rChild))
return compTree(a->rChild, b->lChild);
}
return false;
}
交换二叉树每个结点左孩子和右孩子
void ChangeLR(Bitree &T)
{
Bitree temp;
if(T->lchild==NULL&&T->rchild==NULL)
return ;
else
{
temp=T->lchild;
T->lchild=T->rchild;
T->rchild=temp;
}
ChangeLR(T->lchild);
ChangeLR(T->rchild);
}
双序遍历二叉树
void twoorder(Bitree T)
{
if(T)
{
cout<<T->data;
twoOrder(T->lchild);
cout<<T->data;
twoOrder(T->rchild);
}
}
计算二叉树的最大宽度
int width(Bitree T)
{
if(T==NULL) return 0;
else
{
Bitree Q[]; //Q 是队列,元素为二叉树结点指针
fornt=0;rear=1;last=1;
//front 队头指针, rear队尾指针,last同层最右结点在队列中的位置
temp=0;maxw=0; //temp记录局部宽度,maxw记录最大宽度
Q[rear]=T;
while(fornt<rear)
{
p=Q[front++]; temp++;
if(p->lchild!=NULL) Q[++rear] = p->lchild; //左子女入队
if(p->rchild!=NULL) Q[++rear] = p->rchild; //右子女入队
if(front==last) //一层结束
{
//last 指向下层最右元素,更新当前最大宽度
last=rear;
if(temp>maxw)maxw=temp;
temp=0;
}
}
return maxw;
}
}
统计树中度为1的结点数目
int Level(Bitree T)
{
int num=0;
if(T)
{
QueueInit(Q);QueueIn(Q,bt);
while(!QueueEmpty(Q))
{
p=QueueOut(Q);//出队
//有左孩子没有右孩子,有右孩子没有左孩子
if((p->lchild&&!p->rchild)||(p->rchild&&!p->lchild))num++;
if(p->lchild) QueueIn(Q,p->lchild);
if(p->rchild) QueueIn(Q,p->rchild);
}
}
return num;
}
二叉树的带权路径长度(WPL)是二叉树中所有叶结点的带权路径长度之和。设计算法求WPL
typedef struct Node
{
struct Node* lchild;
struct Node* rchild;
int weight;
}Node,*BitTree;
int sum=0;
int WPL(BitTree &T,int h)
{
if(T==NULL)
{
return ;
}
else
{
if(T->lchild==NULL&&T->rchild==NULL)
{
sum+=level*T->weight;
}
WPL(T->lchild,h+1);
WPL(T->rchild,h+1);
}
return sum;
}
假设一个仅包含二元运算符的算术表达式以链表形式存储在二叉树BT中,写出计算该算术表达式值的算法
ElemType Calculate(BitTree T)
{
Node *p=T;
ElemType val_l,val_r;
if(T)
{
val_l=Calculate(T->lchild);
val_r=Calculate(T->rchild);
switch(T->data)
{
case '+':
value=val_l+val_r;
break;
case '-':
value=val_l-value_r;
break;
case '*';
value=val_l*val_r;
break;
case '/':
value=val_l/val_r;
break;
default:
break;
}
}
return value;
}
非递归后序遍历二叉树
void PostOrder(BitTree T)
{
InitStack(S);
p=T;
r=NULL;
while(p||!IsEmpty(S))
{
if(p)
{
Push(S,p);
p=p->lchild;
}
else
{
GetTop(S,p);//读取栈顶结点
if(p->rchild&&p->rchild!=r) //若右子树存在,且未被访问过
{
p=p->rchild;
}
else
{
Pop(S,p); //将结点弹出
visit(p->data);
r=p; //记录最近访问过的结点
p=NULL; //结点访问完以后,重置p
}
}
}
}
试给出二叉树的自上而下、从右到左的层次遍历算法
void InvertLevel(BitTree bt)
{
Stack S;
Queue Q;
if(bt!=NULL)
{
InitStack(S);
InitQueue(Q);
EnQueue(Q,bt);
while(!IsEmpty(Q))
{
DeQueue(Q,p);
Push(S,p);
if(p->lchild!=NULL)
EnQueue(Q,p->lchild);
if(p->rchild!=NULL)
EnQueue(Q,p->rchild);
}
while(!IsEmpty(S))
{
Pop(S,p);
visit(p);
}
}
}
设计一个非递归算法求二叉树的高度
int Depth(BitTree T)
{
if(!T)
return 0;
int front=-1,rear=-1;
int last=0,level=0;
BitTree Q[MAXSIZE];
BitTree p;
Q[++raer]=T;
while(front<rear)
{
p=Q[++front];
if(p->lchild)
Q[++rear]=p->lchild;
if(p->rchild)
Q[++rear]=p->rchild;
if(front==last)
{
level++;
last=rear;
}
}
return level;
}
试编写一个算法,判断给定的二叉树是否是二叉排序树
根据二叉排序树的定义,左子树结点值 < 根结点值 < 右子树结点值,所以对二叉排序树进行中序遍历(LNR),可以得到一个递增的有序序列。因此,对给定的二叉树进行中序遍历,若始终能保持前一个值小于后一个值,则说明该二叉树是一颗二叉排序树
int pre = -32767; //pre为全局变量,保存当前结点中序前驱的值,初始值为-∞
int IsBST(BSTree T)
{
int left, right; //保存左右子树的判断结果
if (T == NULL) //空树也是二叉排序树,返回1
return 1;
else
{
left = IsBST(T->lchild); //判断左子树是否是二叉排序树
if (left == 0 || pre >= T->data) //若左子树返回0或前驱大于等于当前结点
return 0; //则不是二叉排序树,返回0
pre = T->data; //保存当前结点的值
right = IsBST(T->rchild); //判断右子树是否是二叉排序树
//因为执行到这里时,left的值一定为1,如果left为0上面的则if判断为真已经返回0了
//所以最后直接返回右子树的结果就可以判断给定的二叉树是否是二叉排序树了
return right;
}
}
int pre = -32767; //pre为全局变量,保存当前结点中序前驱的值,初始值为-∞
int IsBST(BSTree T)
{
InitStack(S); //初始化栈
BSTree p = T; //p为遍历指针
while(p || !StackEmpty(S)) //树不空或栈不空,则循环
{
if(p) //一路向左
{
push(S, p); //当前结点入栈
p = p->lchild; //左孩子不空,一直向左走
}
else //出栈,并转向出栈结点的右子树
{
pop(S, p); //栈顶元素出栈
if(p->data < pre)
{
//如果当前结点的值小于前驱pre的值,则不是二叉排序树,返回0
return 0;
}
pre = p->data; //保存当前结点的值
p = p->rchild; //向右子树走,p赋值为当前结点的右孩子
} //返回while循环继续进入if-else语句
}
return 1; //是二叉排序树,返回1
}
已知深度为h的二叉树采用顺序存储结构已存放于数组BT[1:2^h-1]中,请写一非递归算法产生该二叉树的二叉链表结构。设二叉链表中链结点的构造为(lchild,data,rchild),根结点所在链结点的指针由T给出。
typedef struct
{
BiTree bt;
int num;
}tnode
tnode Q[maxsize];
void creat(BiTree T,ElemType BT[], int h)
{
tnode tq;
int len=pow(2,h)-1;
T=(BiTree)malloc(sizeof(BiNode));
T->data=BT[1];
tq.bt=T;
tq.num=1;
Q[1]=tq;
front=0;
rear=1;
while(front!=rear)
{
front=(front+1)%maxsize;
tq=Q[front];
p=tq.bt;
i=tq.num;
if(BT[2*i]=='#'||2*i>len)
{
p->lchild=NULL;
}
else
{
p->lchild=(BiTree)malloc(sizeof(BiNode));
p->lchild->data=BT[2*i];
tq.bt=p->lchild;
tq.num=2*i;
rear=(rear+1)%maxsize;
Q[rear]=tq;
}
if(BT[2*i+1]=='#')
{
p->rchild=NULL;
}
else
{
p->rchild=(BiTree)malloc(sizeof(BiNode));
p->rchild->data=BT[2*i+1];
tq.bt=p->child;
tq.num=2*i+1;
rear=(rear+1)%maxsize;
Q[rear]=tq;
}
}
}
在一棵二叉链表表示的二叉树中,root为根结点,p和q为二叉树中两个结点,编写程序,求距离它们最近的共同祖先,并写出算法思想
int ifhave(TreeNode* root,int o1, int o2){
if(root==nullptr)
return 0;
if(root->val==o1)
return o1;
else if(root->val==o2)
return o2;
int left=ifhave(root->left,o1,o2);
int right=ifhave(root->right,o1,o2);
if(left>=1&&right==0) //root左边有,右边没有,那么祖先已经找到了,就是左边返回的值
return left;
if(left==0&&right>=1) //同理,root左边没有,右边有,那么祖先已经找到了,就是右边返回的值
return right;
if(left&&right>=1) //root的左边也有,右边也有,那么就是root
return root->val;
return 0; //左右都没有的话,return 0
}
在二叉树中查找值为x的结点,试编写算法打印值为x的结点的所有祖先,假设值为x的结点不多于一个
int FindX(BitTree T,ElemType x)
{
if(T==NULL)
return ;
if(T!=NULL)
{
L=FindX(T->leftchild,x);
R=FindX(T->rightchild,x);
if(L||R||T->data==x)
{
cout<<T->data;
return 1;
}
}
return 0;
}
已知二叉树采用二叉链表存储,设计算法以输出二叉树T中根结点到每个叶子结点的路径
void OutputPath(BitTree T,BitTree *Q,int pos)
{
Q[pos]=T;
BitTree T;
t=Q[pos];
if(!t->lchild&&!t->rchild)
{
int i;
for(i=0;i<=pos;i++)
cout<<Q[i]->data;
cout<<endl;
}
else
{
if(t->lchild)
OutputPath(t->lchild,Q,pos+1);
if(t->rchild)
OutputPath(t->rchild,Q,pos+1);
}
}
线索二叉树
typedef struct ThreadNode
{
ElemType data;
struct ThreadNode *lchild,*rchild;
int ltag,rtag;
}ThreadNode,*ThreadTree;
//中序遍历对二叉线索树线索化
void InThread(ThreadTree &p,ThreadTree &pre)
{
if(p!=NULL)
{
InThread(p->lchild,pre);
if(p->lchild==NULL)
{
p->lchild=pre;
p->ltag=1;
}
if(pre!=NULL&&pre->rchild==NULL)
{
pre->rchild=p;
pre->rtag=1;
}
pre=p; //标记当前结点为刚刚访问过的结点
InThread(p->rchild,pre); //递归,线索化右子树
}
}
void CreateInThread(ThreadTree T)
{
ThreadTree pre=NULL;
if(T!=NULL)
{
InThread(T,pre);
pre->rchild=NULL; //最后一个结点没有后继,因此置为空
pre->rtag=1;
}
}
void InorderThread(ThreadTree T)
{
ThreadNode p=T->lchild;
while(p!=NULL)
{
while(p->ltag==0)
{
p=p->lchild;
}
cout<<p->data;
while(p->rtag==1&&p!=NULL)
{
p=p->rchild;
cout<<p->data;
}
p=p->rchild;
}
}
串
1、设s、t为两个字符串,分别放在两个一维数组中,m、n分别为其长度,判断t是否为s的子串。如果是,输出子串所在位置(第一个字符),否则输出0
采用BF算法
int finds(char s[],char t[],int m,int n)
{
while(i<=m&&j<=n)
{
if(s[i]==s[j])
{
++i,++j;
}
//回退
else
{
j=1;
i=i-j+2;
}
}
if(j>n)
{
cout<<i-n;
}
else return 0;
}
2、写一个递归算法来实现字符串逆序存储,要求不另设串存储空间
通过递归的递归工作栈,使输入的字符存入到栈当中,改变存储的顺序。
void InvertStore(char a[]){
char ch;
static int i = 0;
cin >> ch;
if(ch != '.'){
InvertStore(a);
a[i++] = ch;
}
a[i] = '\0'; //结束符
}
3、编写算法,实现下面函数的功能。函数void insert(char *s,char *t,int pos)将字符串t插入到字符串s中,插入位置为pos。假设分配字符串s的空间足够让字符串t插入,
void insertss(char *s, char *t, int pos)
{
char *p ,r[5];
int i = 0, lent = 0;
p = s + pos;
while (*p != '\0')
{
r[i++]= *p++;
}
r[i]='\0';
p = s + pos;
while (*t != '\0')
{
*(p++) = *(t++);
lent++;
}
i=0;
p=s+pos+lent;
while (r[i] != '\0')
{
*(p++) = r[i++];
}
puts(s);
}