idk why these stuffs get stashed for so long and I didn't ever commit them

This commit is contained in:
2025-11-06 09:43:54 +08:00
parent 5dbdfef1a1
commit e01c041259
232 changed files with 22806 additions and 1256 deletions

View File

@@ -0,0 +1,112 @@
template <class DT>
struct QNode //结点
{
DT data; //数据域,存储数据元素值
QNode *next;//指针域,指向下一个结点
};
template<class DT>
struct LinkQueue
{
QNode<DT> * front;
QNode<DT> * rear;
};
//【算法3.19】
template <class DT>
void InitQueue(LinkQueue<DT> &Q)//创建空队列
{
Q.front=new QNode<DT>; //创建头结点
if(!Q.front) exit(1); //创建失败,结束运行
Q.front->next=NULL;
Q.rear=Q.front;
}
//【算法3.20】
template <class DT>
void DestroyQueue(LinkQueue<DT> &Q)//释放链队
{
QNode<DT> *p;
while(Q.front)//从头结点开始,依次释放结点
{
p=Q.front;
Q.front=Q.front->next;
delete p;
}
}
//【算法3.21】 入队
template<class DT>
bool EnQueue(LinkQueue<DT> &Q,DT e)
{
QNode<DT> *p;
p=new QNode<DT>; // 创建新结点
if(!p) return false; // 创建失败,结束运行
p->data=e; // 新结点赋值
p->next=NULL; // 链在队尾
Q.rear->next=p;
Q.rear=p;
return true; // 入队成功返回true
}
//【算法3.22】 出队
template<class DT>
bool DeQueue(LinkQueue<DT> &Q,DT &e)
{
QNode<DT> *p;
if(Q.front==Q.rear) return false; //队空返回false
p=Q.front->next; // 取出队元素
e=p->data;
Q.front->next=p->next; //队首元素出队
if(Q.rear==p) //只有一个元素时出队,
Q.rear=Q.front; // 修改队尾
delete p;
return true; // 出队成功返回true
}
//【算法3.23】 取队头元素
template<class DT>
bool GetHead(LinkQueue<DT> Q,DT &e)
{
if(Q.front==Q.rear) return false; // 队空返回false
e=Q.front->next->data;
return true; // 删除成功返回true
}
//取队尾元素
template<class DT>
bool GetTail(LinkQueue<DT> Q,DT &e)
{
if(Q.front==Q.rear) // 队空
return false; // 返回false
e=Q.rear->data; // 获取队尾元素
return true; // 返回true
}
//测队空
template<class DT>
bool QueueEmpty(LinkQueue<DT> Q)
{
if(Q.front==Q.rear) // 队空
return true; //返回true
else //非空
return false; //返回false
}
//显示队列内容
template<class DT>
void DispQueue(LinkQueue<DT> Q)
{
QNode<DT> *p;
p=Q.front->next;
while(p)
{
cout<<p->data<<"\t";
p=p->next;
}
cout<<endl;
}

View File

@@ -0,0 +1,310 @@
/*--------------------------无向图的邻接矩阵表示-----------------------------*/
#define MAX_VEXNUM 20 // 最大顶点数
#define INF 1000 // 无穷大
template <class DT>
struct MGraph // 图的邻接矩阵表示存储定义
{
DT vexs[MAX_VEXNUM]; // 顶点信息
int arcs[MAX_VEXNUM][MAX_VEXNUM];
int vexnum,arcnum; // 顶点数和边数
};
template <class DT>
void DispG(MGraph<DT> G) // 显示图信息
{
int i,j;
DT u,v;
cout<<G.vexnum<<"个顶点:"<<endl;
for(i=0;i<G.vexnum;i++)
cout<<G.vexs[i]<<" ";
cout<<endl;
cout<<G.arcnum<<"条边信息如下:"<<endl;
for(i=0;i<G.vexnum;i++)
{
for(j=i+1;j<G.vexnum;j++)
if (G.arcs[i][j]!=INF)
{
GetVex(G,i,u);
GetVex(G,j,v);
cout<<'('<<u<<","<<v<<","<<G.arcs[i][j]<<")"<<'\t';
}
}
cout<<endl;
}
//算法6.1 顶点定位
template <class DT>
int LocateVex(MGraph<DT> G,DT v)
{
for(int i = 0;i<G.vexnum;i++)
{
if(G.vexs[i] == v)
{
return i;
}
}
return -1;
}
//6.2 创建无向图
template <class DT>
void CreateUDN(MGraph<DT> &G)
{
int i,j,k,weight;
DT v1,v2;
cout<<"请输入无向网的顶点数 "; // 1. 输入顶点数、边数
cin>>G.vexnum ;
cout<<"请输入无向网的边数 ";
cin>>G.arcnum ;
cout<<"请输入"<<G.vexnum<<"个顶点的值(单个字符)"<<endl; // 2. 输入顶点值
for(i = 0;i<G.vexnum;i++)
cin>>G.vexs[i];
for(i=0;i<G.vexnum;i++) // 3.邻接矩阵初始化
for(j=0;j<G.vexnum;j++)
G.arcs[i][j]=INF;
cout<<"请输入各条边的两个邻接点"<<endl; // 4.创建各条边
for( k=0;k<G.arcnum;k++)
{
cout<<"输入第"<<k<<"条边的两个顶点和权值:"<<endl;
cin>>v1>>v2; // 4.1 输入边的两个邻接点和边权值
cin>>weight;
i = LocateVex(G,v1); // 4.2 定位两个邻接点
j = LocateVex(G,v2);
if(i<0 || j<0 || i==j)
{
cout<<"顶点信息错,重新输入!"<<endl;
k--;
continue;
}
G.arcs[i][j]=weight; // 4.3 修改邻接矩阵
G.arcs[j][i]=weight;
}
}
template <class DT>
bool GetVex(MGraph<DT> G, int k, DT &v) // 获取第 u 个顶点值v
{
if(k<0 || k>=G.vexnum) // u不存在返回false
return false;
else
{
v=G.vexs[k];
return true;
}
}
template <class DT>
bool PutVex(MGraph<DT> &G,DT &u,DT v) // 为第u个顶点赋值
{
int k;
k=LocateVex(G,u);
if(k<0 ) // u不存在返回false
return false;
else // u存在赋值
{
G.vexs[k] = v;
return true;
}
}
//算法6.3 按值查找第一邻接点
template <class DT>
int FirstAdjvex(MGraph<DT> G,int u)
{
if(u<0 || u>=G.vexnum) // 顶点不存在
return -1; // 无邻接点,返回-1
for(int j=0;j<G.vexnum;j++) // 扫描邻接矩阵第u行
if(G.arcs[u][j]!=INF) // 如果有非零元,
return j; // 第一个非零元所在列号,为其邻接点序号
return -1; // 否则,无邻接点,返回-1
}
template <class DT>
int NextAdjvex(MGraph<DT> G,int u,int w) //查找第u个顶点邻接点W的下一个邻接点
{
if(u<0 || u>=G.vexnum || w<0
|| w>=G.vexnum || G.arcs[u][w]==INF ) // 参数不合理
return -1; // 无邻接点
for(int j=w+1;j<G.vexnum;j++) // 扫描邻接矩阵第u行w列后的元素
if(G.arcs[u][j]!=INF) // 如果有非零元,
return j; // 第一个非零元所在列号,为其邻接点序号
return -1; // 否则无邻接点,返回-1
}
template <class DT>
bool InsertVex(MGraph<DT> &G,DT v) // 插入值为v的顶点
{
DT w;
int j,weight;
char ans;
if(G.vexnum>=MAX_VEXNUM) // 无存储空间,不能插入
{
cout<<"无存储空间,不能插入!"<<endl;
return false;
}
G.vexs[G.vexnum++]= v; // 顶点信息加入至G.vexs中顶点数增1
for(j=0;j<G.vexnum;j++) // 初始化邻接矩阵最后一行和最后一列值
{
G.arcs[G.vexnum-1][j]=INF;
G.arcs[j][G.vexnum-1]=INF;
}
cout<<"创建边吗Y/N)?"<<endl;
cin>>ans;
while(ans=='Y'|| ans=='y')
{
cout<<"输入另一个顶点值和边的权值"<<endl;
cin>>w>>weight;
j=LocateVex(G,w);
if(j>=0) // 顶点存在
InsertArc(G,v,w,weight);
else
cout<<w<<"顶点不存在!";
cout<<"继续创建边吗Y/N)?"<<endl;
cin>>ans;
};
return true;
}
template <class DT>
bool InsertArc(MGraph<DT> &G,DT v,DT w,int weight) // 在值为v、w顶点间加边
{ int i = LocateVex(G,v);
int j = LocateVex(G,w);
if(i<0 || j<0 || i==j) // 顶点不存在或两端点相同
{
cout<<"\n顶点不存在,或两顶点相同,不能插入!"<<endl;
return false; // 不能插入边返回false
}
if(G.arcs[i][j]!=INF)
{
cout<<"\n边已存在,不能插入!"<<endl;
return false;
}
G.arcs[i][j]=weight;
G.arcs[j][i]=weight;
G.arcnum++;
return true;
}
template <class DT>
bool DeleteArc(MGraph<DT> &G,DT v,DT w) // 按顶点值删除边
{
int i = LocateVex(G,v);
int j = LocateVex(G,w);
if(i<0||j<0||i == j) // 边不存在返回false
{
cout<<"边不存在!"<<endl;
return false;
}
G.arcs[i][j]=INF; // 置邻接矩阵第 i 行第 j 列为零
G.arcs[j][i]=INF; // 置邻接矩阵第 i 列第 j 行为零
G.arcnum--; // 边数减1
return true;
}
template <class DT>
bool DeleteVex(MGraph<DT> &G,DT v) // 按值删除顶点
{
int i,j;
DT w;
i = LocateVex(G,v); // 顶点定位
if(i<0)
{
cout<<"顶点不存在!"<<endl; // 顶点不存在
return false;
}
for(j=0;j<G.vexnum;j++) // 删除与顶点v相连的边
{
if(G.arcs[i][j]!=INF)
{
GetVex(G,j,w);
DeleteArc(G,v,w);
}
}
for(j=i+1;j<G.vexnum;j++) // 排在顶点v后面的顶点前移
{
G.vexs[j-1] = G.vexs[j];
}
G.vexnum--;
return true;
}
// 算法6.10
template <class DT>
void DFS2(MGraph<DT> G,int v) // 连通图深度优先遍历
{
int w;
visited[v] = true; // 先访问index
cout<<G.vexs[v];
for(w=0;w<G.vexnum;w++)
{
if(G.arcs[v][w]!=INF && !visited[w] )
DFS2(G,w);
}
//cout<<endl;
}
// 算法6.9
template <class DT>
void DFSTraverse(MGraph<DT> G) // 非连通图深度优先遍历
{
int i;
for(i=0;i<G.vexnum;i++) // 访问标志初始化
visited[i]=0;
for( i=0;i<G.vexnum;i++) // 对未被访问的顶点
{
if(!visited[i])
DFS2(G,i); // 进行深度优先递归
}
cout<<endl;
return ;
}
// 算法 6.11 广度优先遍历
template <class DT>
void BFS(MGraph<DT> G,int v)
{
int w;
LinkQueue<int> Q; // 创建一个队列
InitQueue(Q);
cout<<G.vexs[v]; // 访问顶点v
visited[v]=true; // 做访问标志
EnQueue(Q,v); // 入队
while(!QueueEmpty(Q)) // 队非空
{
DeQueue(Q,v); // 出队
for(w=FirstAdjvex(G,v);w>=0;w=NextAdjvex(G,v,w)) // 遍历v的邻接点
if(!visited[w]) // 未被访问
{
cout<<G.vexs[w]; // 访问
visited[w]=true; // 做访问标志
EnQueue(Q,w); // 入队
}
}
}
// 算法6.12
template <class DT>
void BFSTraverse(MGraph<DT> G) // 广度优先遍历
{
int i;
for(i=0;i<G.vexnum;i++) // 访问标志初始化
visited[i]=0;
for(i=0;i<G.vexnum;i++) // 对未被访问的结点
{
if(!visited[i])
BFS(G,i); // 进行BFS遍历
}
}

View File

@@ -0,0 +1,217 @@
#include<string>
#include "LinkQueue.h"
#include "Mgraph.h"
#include <iostream>
using namespace std;
const MAX_ARCNUM=50;
// 最小生成树
//算法6.18 Prim算法
struct CEdge // 候选边存储
{
int adjvex; // U中集合点
int lowcost; // 最小边的权值
};
int minEdge(CEdge closeEdge[],int n)
{
int i, k=0;
int min = INF;
for ( i=0; i<n; i++) //求出与U权值最小的点 权值为0的代表在集合U
{
if (closeEdge[i].lowcost != 0 && closeEdge[i].lowcost<min)
{
min = closeEdge[i].lowcost;
k = i;
}
}
return k;
}
template<class DT>
bool Prim_MST(MGraph<DT> G, DT v) // 从顶点v开始计算的最小生成树
{
CEdge closeEdge[MAX_VEXNUM];
int i,j,k,mincost = 0;
k=LocateVex(G,v);
if(k==-1) // 顶点不存在
{
cout<<"顶点不存在!"<<endl;
return false;
}
for (i = 0; i < G.vexnum; i++) // 辅助数组初始化
if(i!=k)
{
closeEdge[i].adjvex = k; // u中的点
closeEdge[i].lowcost = G.arcs[k][i];
}
closeEdge[k].lowcost=0; // 初始 U={v}
cout << "\n Prim最小生成树的边:"<< endl;
for (i = 1; i < G.vexnum; i++) // 选择其余G.vexnum-1个顶点
{
k=minEdge(closeEdge,G.vexnum); // 输出选择的权值最小的边
cout << "(" <<G.vexs[closeEdge[k].adjvex]<< "," << G.vexs[k]
<<"): "<<closeEdge[k].lowcost<<endl;
mincost+=closeEdge[k].lowcost;
closeEdge[k].lowcost=0;
for (j = 0; j<G.vexnum; j++) // 更新最小边
{
if (closeEdge[j].lowcost != 0 && G.arcs[k][j]<closeEdge[j].lowcost)
{
closeEdge[j].adjvex = k;
closeEdge[j].lowcost= G.arcs[k][j];
}
}
}
cout << "\n Prim最小生成树权值之和:" << mincost << endl;
return true;
}
// Kruskal算法
struct Edge{ // 存储边的信息
int u,v;
int cost;
};
//Edge edge[MAX_ARCNUM];
void Sort(Edge edge[],int n) // 冒泡排序
{
int i,j;
//int k;
Edge temp;
bool exchange;
for(i=0,exchange=true;i<n-1 && exchange; i++) // 一趟排序工作如下:
{
exchange=false; // 1.设置交换标志初值为无交换
for(j=0;j<n-i-1;j++) // 2.从表首开始两两比较
{
if (edge[j].cost>edge[j+1].cost) // 2.1相邻元素逆序,互换位置
{
temp=edge[j];edge[j]=edge[j+1];edge[j+1]=temp; // R[j]<-->R[j+1]
exchange=true; // 2.2 交换标志改为true
}
}
}
}
int parent[MAX_VEXNUM];
void Connect(int &x,int &y) // 连通分量标识
{
if(x<y)
y=x;
else
x=y;
}
//算法6.19 克鲁斯卡尔Kruskal算法
template <class DT>
bool Kruskal_MST(MGraph<DT> G) // 返回生成代价
{
int mincost=0,Num_Edge=0;
char u,v;
int i,j,k=0;
Edge edge[MAX_ARCNUM];
for(i=0;i<G.vexnum;i++) // 从邻接矩阵获取边信息
for(j=0;j<G.vexnum;j++)
{
if(i<j && G.arcs[i][j]!=INF)
{
edge[k].u=i; // 存储边的信息
edge[k].v=j;
edge[k].cost=G.arcs[i][j];
k++;
}
}
Sort(edge,G.arcnum); // 边排序
for(i=0;i<G.vexnum;i++) // 连通分量初始化
{
parent[i]=i;
}
cout << "\n Kruskal 最小生成树的边:"<< endl;
for(i=0;i<G.arcnum;i++) // 从小到考察选取n-1条边
{
j=edge[i].u;
k=edge[i].v;
int vx1=parent[j]; // 获取边起点、终点所在的连通分量标志
int vx2=parent[k];
if(vx1!=vx2) // 如果不属于同一个连通分量, 生成边
{
GetVex(G,j,u);
GetVex(G,k,v);
cout<<"("<<u<<","<<v<<"):"<<G.arcs[j][k]<<endl;
Connect(parent[j],parent[k]); // 合并连通分量
mincost+=edge[i].cost;
Num_Edge++; // 已找到的边数+1
if(Num_Edge==G.vexnum-1)
break;
}
}
if(Num_Edge!=G.vexnum-1) // 判断最小生成树的查找情况
{
cout<<"非连通图,无最小生成树!"<<endl;
return false;
}
else
{
cout<<"\nKruskal最小生树权值为"<<mincost<<endl;
return true;
}
}
void DispMenu()
{
cout<<"\n 请选择你要的操作"<<endl;
cout<<" 1. 建立无向网"<<endl;
cout<<" 2. Prinmt算法"<<endl;
cout<<" 3. Kruskal算法"<<endl;
cout<<" 4. 显示网"<<endl;
cout<<" 0. 退出"<<endl;
}
bool visited[MAX_VEXNUM]={false};
void main()
{
char v;
//int k,weight;
MGraph<char> G;
int choice;
do
{
DispMenu();
cin>>choice;
switch(choice)
{
case 1: // 创建无向网
CreateUDN(G);
cout<<endl;
cout<<"创建的网为:"<<endl;
DispG(G);
break;
case 2: // Prinmt算法
cout<<"请输入起始计算顶点: ";
cin>>v;
Prim_MST(G,v);
break;
case 3: // Kruskal算法
Kruskal_MST(G);
cout<<endl;
break;
case 4: // 显示网
DispG(G);
cout<<endl;
break;
case 0:
cout<<"结束运行Bye-Bye!"<<endl;
break;
default:
cout<<"选择不合理,请重选!"<<endl;
}//case
}while(choice!=0);
}//main