c++数据结构小助手 : 可视化树与图工具
基于 graphics.h;
从文件 graph.txt 读图
格式如下:
命名:graph.txt
第一行,两个整数,n个点和m条边,边全都是有向边
第二行到第m+1行
每行三个整数
a b c
表示从a到b有一条权重为c的边
无向边就是两条有向边
效果:
左键点击点可以拖动改变布局
图中箭头是算出来的
#include <iostream>
#include <stdio.h>
#include <graphics.h>
#include <unordered_map>
#include <vector>
#include <queue>
#include <cmath>
#include <cstring>
#include <conio.h>
#include <functional>
#include <stdio.h>
#include <io.h>
#include <string>
#include <fstream>
#include <sstream>
#include<time.h>
/*
从文件读取
本人平时不太喜欢写注释,特别是在写一些比较小的程序的
左键点击图中的点有惊喜
*/
#define MAX_LINE 1024
#define MAXR 100
#define MINR 1
using namespace std;
#define WINDOWW 500
#define WINDOWH 500
#define X_AXIS WINDOWH/2
#define Y_AXIS WINDOWW/2
#define MIDW WINDOWW/2
#define MIDH WINDOWH/2
#define PI 3.1415926
#define VER_SIZE 10
#define MAX_VERS 2000
typedef pair<int, int> pii;
typedef pair<int, pii> pi_ii;
int n, m;
double toRadius(double degree){ // 角度转弧度
double flag = (degree < 0) ? -1.0 : 1.0;
if (degree < 0){
degree = degree*-1.0;
}
double res = flag*(degree*PI) / 180;
return res;
}
void intToChar(int i, TCHAR res[]){ // int转char
char t[33];
int p = 0, q = 0;
while (i){
t[p++] = i % 10 + '0';
i /= 10;
}
for (int i = p - 1; i >= 0; i--){
res[q++] = t[i];
}
res[q] = '\0';
}
bool drawArray(int x1, int y1, int x2, int y2, double breath = 15){ // 画箭头
int xa, ya, xb, yb, xt, yt;
if (x1 == x2){
xt = x1;
if (y1 > y2){
y1 -= breath;
y2 += breath;
yt = y2 + breath / 2;
}
else{
y1 += breath;
y2 -= breath;
yt = y2 - breath / 2;
}
xa = xt - breath / 2;
ya = yt;
xb = xt + breath / 2;
yb = yt;
}
else{
double k = (double)(y1 - y2) / (double)(x1 - x2);
double dx, dy;
dx = breath / sqrt(1 + k*k);
dy = fabs(k)*dx;
if (k >= 0){
if (y1 < y2){
x1 += dx;
y1 += dy;
x2 -= dx;
y2 -= dy;
xt = x2 - dx / 2;
yt = y2 - dy / 2;
}
else{
x2 += dx;
y2 += dy;
x1 -= dx;
y1 -= dy;
xt = x2 + dx / 2;
yt = y2 + dy / 2;
}
xa = xt + dy / 3;
ya = yt - dx / 3;
xb = xt - dy / 3;
yb = yt + dx / 3;
}
else{
if (y1 > y2){
x1 += dx;
y1 -= dy;
x2 -= dx;
y2 += dy;
xt = x2 - dx / 2;
yt = y2 + dy / 2;
}
else{
x2 += dx;
y2 -= dy;
x1 -= dx;
y1 += dy;
xt = x2 + dx / 2;
yt = y2 - dy / 2;
}
xa = xt - dy / 3;
ya = yt - dx / 3;
xb = xt + dy / 3;
yb = yt + dx / 3;
}
}
POINT pts[] = { { x2, y2 }, { xa, ya }, { xb, yb } };
fillpolygon(pts, 3);
line(x1, y1, x2, y2);
return true;
}
unordered_map<int, pii> initVerXY(int vertices){
double D_degree = 360.0 / (double)vertices;
double degree = 0;
unordered_map<int, pii> vers;
for (int i = 1; i <= vertices; i++){
int verY, verX;
double k = tan(toRadius(degree));
if ((0 <= degree&°ree <= 90) || (270 < degree&°ree <= 360)){
if (-1 <= k && k <= 1){
verX = (WINDOWW - MIDW) / 2;
verY = k*verX;
}
else{
verY = (WINDOWH - MIDH) / 2;
if (k < 0) verY = -verY;
verX = verY / k;
}
}
else{
if (-1 <= k && k <= 1){
verX = (MIDW - WINDOWW) / 2;
verY = k*verX;
}
else{
verY = (MIDH - WINDOWH) / 2;
if (k < 0) verY = -verY;
verX = verY / k;
}
}
degree += D_degree;
int num1 = rand() % (MAXR - MINR) + MAXR;
int num2 = rand() % (MAXR - MINR) + MAXR;
int num3 = rand() % (MAXR - MINR) + MAXR;
int num4 = rand() % (MAXR - MINR) + MAXR;
verX = verX + num1 - num3;
verY = verY + num2 - num4;
vers[i] = { verX + MIDW, verY + MIDH };
}
return vers;
}
bool drawGraph(unordered_map<int, pii> vers, priority_queue<pi_ii> sides){
for (int i = 1; i <= vers.size(); i++){
setcolor(LIGHTRED);
TCHAR s[32];
intToChar(i, s);
int verX = vers[i].first, verY = vers[i].second;
circle(verX, verY, VER_SIZE);
setcolor(WHITE);
settextcolor(GREEN);
outtextxy(verX - 4, verY - 7, s);
settextcolor(WHITE);
}
while (sides.size()){
pi_ii t = sides.top();
sides.pop();
int verA = t.second.first;
int verB = t.second.second;
int len = t.first;
setcolor(YELLOW);
drawArray(vers[verA].first, vers[verA].second, vers[verB].first, vers[verB].second);
setcolor(WHITE);
TCHAR s[32];
intToChar(len, s);
outtextxy(vers[verA].first + vers[verB].first >> 1, vers[verA].second + vers[verB].second >> 1, s);
}
return true;
}
template<class out_type, class in_value>
out_type convert(const in_value & t)
{
stringstream stream;
stream << t;// 向流中传值
out_type result;// 这里存储转换结果
stream >> result;// 向result中写入值
return result;
}
bool checkIfGetVer(int vx, int vy, int mx, int my){
double d;
d = sqrt((double)(vx - mx)*(vx - mx) + (double)(vy - my)*(vy - my));
if (d < VER_SIZE) return true;
return false;
}
void dragMove(unordered_map<int, pii> vers, priority_queue<pi_ii> sides){
MOUSEMSG clickdown;
MOUSEMSG down;
while (true){
clickdown = GetMouseMsg();
switch (clickdown.uMsg){
case WM_LBUTTONDOWN: // left click
for (int i = 1; i <= vers.size(); i++){
if (checkIfGetVer(vers[i].first, vers[i].second, clickdown.x, clickdown.y)){
int flag = 0;
while (true){
down = GetMouseMsg();
switch (down.uMsg){
case WM_MOUSEMOVE:
BeginBatchDraw(); // double huan chong
cleardevice();
vers[i].first = down.x;
vers[i].second = down.y;
drawGraph(vers, sides);
EndBatchDraw();
break;
case WM_LBUTTONDOWN:
flag = 1;
break;
}
if (flag)break;
}
}
}
break;
case WM_LBUTTONUP:
break;
}
}
}
int main(){
srand(time(0));
char buf[MAX_LINE];
string buff;
FILE *fp;
int len;
if ((fp = fopen("graph.txt", "r")) == NULL)
{
perror("fail to read");
exit(1);
}
fgets(buf, MAX_LINE, fp);
len = strlen(buf);
buf[len - 1] = '\0';
buff = buf;
stringstream sstream;
sstream << buff;
string t;
sstream >> t;
n = convert<int>(t);
//printf("%d ", n);
sstream >> t;
m = convert<int>(t);
//printf("%d\n", m);
priority_queue<pi_ii> sides;
while (fgets(buf, MAX_LINE, fp) != NULL)
{
stringstream sstream;
string t;
len = strlen(buf);
buf[len - 1] = '\0';
int a, b, c;
buff = buf;
sstream << buff;
sstream >> t;
a = convert<int>(t);
sstream >> t;
b = convert<int>(t);
sstream >> t;
c = convert<int>(t);
sides.push({ c, { a, b } });
printf("起点:%d,终点:%d,权重:%d\n", a, b, c);
}
unordered_map<int, pii> vers;
vers = initVerXY(n);
initgraph(WINDOWW, WINDOWH);
//circle(0, 0, 10);
drawGraph(vers, sides);
dragMove(vers, sides);
//while (1);
// printGraph(n, sides);
// dragMove();
closegraph();
getchar();
getchar();
return 0;
}