斯坦福CS106L-C++作业1——graph drawing problem

参考资料:
斯坦福CS106L

此次作业主要是stream和vector的运用。

  • 问题描述:

一个图通常可以画成很多形式,有些形式比较任意“看懂”,尝试将一幅图画得比较通俗。
下图很难看出什么结构



下图跟上图是一样的,但结构明显好多了。


  • 算法:

没有一种通用可以解决所有画图问题的算法,每种算法都有自己画得好的图,也有画得不好的图,这里采用的是force-directed layout algorithm。
画图的算法可以从减少交叉和增加对称性入手,本作业的算法用
另外两条准则:
1、相连的节点有吸引力
2、没有相连的节点有排斥力
程序采用迭代的方式,首先初始安排节点,然后更具以上两条原则计算各自节点上的”力“,力的计算可以有多种方式,根据”力“新节点的位置。
初始安排节点:可以均匀摆放在一个圆上。


何时停止迭代:让用户选择迭代多久
计算力:Fruchterman-Reingold algorithm,排斥力跟距离成反比(注意系数一般是10-3),排斥力在任意两个节点之间,吸引力跟距离的平方成正比(也有一个一般是10-3的系数),吸引力在每条边的两端点之间。
移动:根据净力的大小移动每个点。

  • 作业任务

1.用户输入要画图的图描述文件
2.输入要运行的时间t
3.初始化每个点初试位置
4.在时间t内计算力,然后移动各节点

  • 代表图的数据结构

Node:包含每个节点横纵坐标x,y的结构体。

/**
 * Type: Node
 * -----------------------------------------------------------------------
 * A type representing a node in a graph.  Each node stores only the x and
 * y coordinates of where the node is in the plane; all other information
 * about the node is stored implicitly by its position in the SimpleGraph
 * list of nodes.
 */
struct Node {
  double x, y;
};

Edge:记录起点终点的序号

/**
 * Type: Edge
 * -----------------------------------------------------------------------
 * A type representing an edge in the graph.  It stores its endpoints by
 * the indices in which they occur in the SimpleGraph's list of Nodes.
 */
struct Edge {
  std::size_t start, end;
};

SimpleGraph:点和边

/**
 * Type: SimpleGraph
 * -----------------------------------------------------------------------
 * A type representing a simple graph of nodes and edges.
 */

struct SimpleGraph {
    std::vector<Node> nodes;
    std::vector<Edge> edges;
};

图描述文件:下面代表8个定点,接着每行两个数字表示对应序号的点之间有一条边。

8
0 1
1 2
2 3
3 0
4 5
5 6
6 7
7 4
0 4
1 5
2 6
3 7
  • 任务分解
    1、从磁盘读取图文件
#include <string>
#include <sstream>
#include <fstream>

SimpleGraph* readGraphFromDisk() {
    std::string fileName;
    std::ifstream is;

    while (true) {
        std::cout << "input file name:" << std::endl;
        //记得#include <sstream>
        std::getline(std::cin, fileName);

        is.open(fileName);
        if (!is) {
            std::cout << "file doesn't exist!" << std::endl;
        } else {
            break;
        }
    }

    std::size_t n_nodes;
    Edge edge;
    SimpleGraph *p_G =  new SimpleGraph();

    // 读取顶点数
    is >> n_nodes;
    p_G->nodes.resize(n_nodes);

    // 依次读取边
    while (is >> edge.start >> edge.end) {
        p_G->edges.push_back(edge);
    }
    return p_G;
}

2、初始化点的位置


#include <cmath>
const double PI = 3.14159265358979323;
void InitNode(SimpleGraph& G){
    std::size_t n_nodes = G.nodes.size();

    for(std::size_t i=0;i<n_nodes;i++){
        G.nodes.at(i).x = cos(2*PI*i/n_nodes);
        G.nodes.at(i).y = sin(2*PI*i/n_nodes);
    }
}

3、时间的计算:

#include <ctime>
    time_t startTime = time(NULL);
    double elapseTime = 0;
    do{
        UpdateGraph(*p_G);
        DrawGraph(*p_G);
        elapseTime = difftime(time(NULL),startTime);
    }while(elapseTime >= excuteTimeInS);

4、算法具体实现:

#define K_REPL 0.001
#define K_ATTR 0.001
void UpdateGraph(SimpleGraph& G){
    int N_nodes = G.nodes.size();
    std::vector<Node> nodes_forces(N_nodes,{0.0,0.0});

    int start,end;
    double force,angle;

    //排斥力
    for(int i=0;i<N_nodes;i++)
        for(int j=i+1;j<N_nodes;j++){
            start = i;
            end = j;

            force = K_REPL/sqrt(CalcSquareDistance(G,start,end));
            angle = atan2(G.nodes[end].y - G.nodes[start].y,G.nodes[end].x - G.nodes[start].x);
            nodes_forces[start].x -= force*cos(angle);
            nodes_forces[start].y -= force*sin(angle);
            nodes_forces[end].x += force*cos(angle);
            nodes_forces[end].y += force*sin(angle);
        }


    //吸引力
    for(Edge edge:G.edges)
    {
        start = edge.start;
        end = edge.end;

        force = CalcSquareDistance(G,start,end) * K_ATTR;
        angle = atan2(G.nodes[end].y - G.nodes[start].y,G.nodes[end].x - G.nodes[start].x);
        nodes_forces[start].x += force*cos(angle);
        nodes_forces[start].y += force*sin(angle);
        nodes_forces[end].x -= force*cos(angle);
        nodes_forces[end].y -= force*sin(angle);
    }

    //根据力进行调整位置
    for(int i=0;i<N_nodes;i++){
        G.nodes[i].x += nodes_forces[i].x;
        G.nodes[i].y += nodes_forces[i].y;
    }
}

main函数

// Main method
int main() {
    SimpleGraph *p_G;

    Welcome();

    p_G = readGraphFromDisk("127binary-tree");
    InitNode(*p_G);
    DrawGraph(*p_G);

    double excuteTimeInS;
    std::cout << "input excute time in seconds:" << std::endl;
    std::cin >> excuteTimeInS;

    time_t startTime = time(NULL);
    while(difftime(time(NULL),startTime) <= excuteTimeInS){
        UpdateGraph(*p_G);
    }
    DrawGraph(*p_G);

    std::cout << "finish!" << std::endl;

    delete p_G;
    return 0;
}
  • 实验结果:
    127binary-tree:


    初试化

    3s后

    10s后
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 220,699评论 6 513
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 94,124评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 167,127评论 0 358
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 59,342评论 1 294
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,356评论 6 397
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 52,057评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,654评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,572评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 46,095评论 1 318
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,205评论 3 339
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,343评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 36,015评论 5 347
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,704评论 3 332
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,196评论 0 23
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,320评论 1 271
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,690评论 3 375
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,348评论 2 358