如何讓數據結構可視化? 1. 安裝 2. 渲染 3. 編寫代碼 4. 坑 3.4.2 命名 3.5 代碼 寫在最後

當我們實現一個比較複雜的數據結構,比如二叉樹、圖、跳錶,Debug的時候怎麼驗證自己寫的函數對不對呢?

一個方法是將數據結構可視化,與理論上的結果比較即可。

請出主角:Graphviz,帶一種解釋語言dot,可以用簡明的代碼作圖。
之所以推薦這個是因爲它可以自動排版

1. 安裝

官網下載鏈接[1]:http://www.graphviz.org/download/

作者系統爲win10,其他操作系統應該大同小異。
安裝時需要勾選添加環境變量

2. 渲染

有vscode的讀者可以安裝一個vscode插件:


安裝完成後,新建一個.dot文件,右上角會出現一個渲染按鈕:


沒有vscode的讀者可以使用命令手動渲染:
dot -Tpng 你的代碼文件名 -o 輸出圖片文件名

3. 編寫代碼

一個空的dot代碼(什麼都不渲染):

digraph {
}

如圖左上,可以使用下面代碼,來創建一個名字爲a的結點

digraph {
  a
}

如圖左下,通過label的修改可以改動結點顯示的文字。
如圖右上,通過style = "dotted"可以讓其外側圈邊成虛線(可以用來顯示NULL結點)
代碼中的引號疑似不是必須的,建議保留。

digraph {
    a[label = "文字", style = "dotted"]
}

通過結點名稱 -> 結點名稱來創建一條線。
同理也可以使用dotted,(虛線用於連接NULL結點)。
這個taillabel可以在靠近第一個結點處顯示一個數值(可用於顯示結點中的一個數值)

digraph {
    node1[label = "A"]
    node2[label = "B"]
    node1 -> node2[style = dotted, taillabel = "0"]
}

tips:建議將結點的數據,也就是value,拿到node[label = ]中顯示,最突出、顯眼。

4. 坑

3.4.1 NULL補位

NULL,空指針,在C++中被定義爲0
一個正常結點缺失左或右子結點時,會使用NULL指針來填補空缺。

正是因爲其自動排版的功能,會導致一些坑。
舉個例子,我們要畫一個這樣的二叉樹:

    1
    |
 -------
|       |
0    沒有右孩子(NULL結點)

因爲我們不能使用開頭爲數字作爲變量名,所以我們的命名規則爲:n + 數字。

繪畫效果:


我們發現,如果不使用一個結點NULL來補位,樹被拉成了一個鏈。
我們只需要使用一層NULL結點來補位,這樣結構就渲染正常了。

3.4.2 命名

兩個結點名字相同,會被判定爲一個結點:


雖然這種情況在二叉搜索樹中不存在,但是這裏還是提一下。

怎麼區分不同的結點呢?我們可以通過C++程序中結點的指針來命名。
結點名稱:n + 指針
即使兩個結點存儲內容相同,但是在電腦中的內存地址一定不同

但是NULL結點都會被命名爲n0,無法區分,怎麼辦呢?
我這裏使用的解決方法:NULL結點命名規則爲n + 葉子結點指針 + 是左子結點還是右子結點


3.5 代碼

這個代碼是基於Part 1中結點的定義來實現的。

void DEBUG() { // 使用了part 2中的軟件來繪圖,調試神器
    FILE *fp = NULL;
    fp = fopen("./output.dot", "w"); // ./output.dot 爲輸出的文件名
    fprintf(fp, "digraph {\n");
 
    deque<node*> q; // 前序遍歷,使用隊列實現
    node *current;
    q.push_back(root);
    while (!q.empty()) {
        current = q.front();
        q.pop_front();
        if (current == NULL) {
            continue;
        }
        fprintf(fp, "\tn%d[label = \"%d\"]\n", current, current->value);
        for (int i = 0; i < 2; ++i) {
            if (current->child[i]) {
                fprintf(fp, "\tn%d -> n%d[style = blod]\n", current, current->child[i]);
                q.push_back(current->child[i]);
            } else {
                fprintf(fp, "\tnull%d%d[label = \"NULL\", style = dotted]\n", current, i);
                fprintf(fp, "\tn%d -> null%d%d[style = dotted]\n", current, current, i);
            }
        }
    }
    fprintf(fp, "}");
    fclose(fp);
}

寫在最後

傻姑粉絲福利:更多一線大廠面試題,高併發等主流技術資料盡在下方
github直達地址一線大廠面試題,高併發等主流技術資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章