C調(diào)用graphviz繪制堆

之前的博客http://blog.csdn.net/socho/article/details/51565498
《對(duì)"堆"的理解》中打印堆是在終端中,不是很直觀,發(fā)現(xiàn)一個(gè)可以生成圖片的利器graphviz,于是用c語(yǔ)言調(diào)用下,程序運(yùn)行中生成圖片,特別直觀了。
以上是用終端打印出來(lái)的,發(fā)現(xiàn)了一個(gè)繪圖利器graphviz,可以把堆畫(huà)出來(lái)。安裝這個(gè)軟件什么的就不講了,自己百度,這里默認(rèn)已經(jīng)安裝好了。所以,對(duì)以上代碼更新

#include <stdio.h>
#define N 12
void printHeap(int A[], char *filename, int color_point){
    ///// 這里是在終端打印節(jié)點(diǎn) /////
    printf("            -----------%d-----------\n", A[1]);
    printf("           /                       \\\n");
    printf("      ----%d----               ----%d----\n", A[2], A[3]);
    printf("     /          \\             /          \\\n");
    printf("  --%d--     ---%d---     ---%d          %d\n", A[4], A[5], A[6], A[7]);
    printf(" /      \\   /        \\   /\n");
    printf("%d      %d %d        %d %d\n", A[8], A[9], A[10], A[11] , A[12]);

    ///// 以下是輸出到heap_*.dot文件中,供用graphicvz生成png圖片節(jié)點(diǎn)表示法用 /////
    int i = 0;
    FILE* fp = fopen(filename, "w+"); //dot -Tpng heap.dot -o heap.png
    if( NULL == fp)
    {
        fprintf(stderr, "打開(kāi)文件描述符失敗\n");
        return;
    }
    fprintf(fp, "digraph {\n");
    for ( i = 1; i <= N/2; i++)
    {
        if (i*2 <= N)
        {
            fprintf(fp, " %llu -> %llu\n", A[i], A[i*2]) ;
        } else {
            fprintf(fp, " %llu -> null [style = dotted]\n", A[i]); // 設(shè)置null節(jié)點(diǎn)連接線(xiàn)的屬性
        }
        if (i*2+1 <= N){
            fprintf(fp, " %llu -> %llu\n", A[i], A[i*2+1]);
        } else {
            fprintf(fp, " %llu -> null [style = dotted]\n", A[i]);
        }
    }
    if (0 != color_point) // 需要染色的節(jié)點(diǎn)
    {
        fprintf(fp, ";\n %d [color = red]\n", color_point);
    }
    fprintf(fp, ";\n null [style = dotted]}\n"); // 設(shè)置null節(jié)點(diǎn)的屬性
    fclose(fp);
}
void swap(int A[], int t, int i){
    A[t] = A[t] ^ A[i];
    A[i] = A[t] ^ A[i];
    A[t] = A[i] ^ A[t];
}
/* 向下調(diào)整。
 * @param A 堆的線(xiàn)性存儲(chǔ)方式,數(shù)組
 * @param n 節(jié)點(diǎn)總數(shù)
 * @param i 需要向下調(diào)整的節(jié)點(diǎn)編號(hào)
 */
void godown(int A[], int n, int i) //傳入一個(gè)需要向下調(diào)整的結(jié)點(diǎn)編號(hào)i,這里傳入1,即從堆的頂點(diǎn)開(kāi)始向下調(diào)整 
{
    int t,flag=0,count=0;//flag用來(lái)標(biāo)記是否需要繼續(xù)向下調(diào)整 
    //當(dāng)i結(jié)點(diǎn)有兒子的時(shí)候(其實(shí)是至少有左兒子的情況下)并且有需要繼續(xù)調(diào)整的時(shí)候循環(huán)窒執(zhí)行
    while( i*2<=n && flag==0 )
    {        
        //首先判斷他和他左兒子的關(guān)系,并用t記錄值較小的結(jié)點(diǎn)編號(hào) 
        if( A[i] > A[i*2] )
            t=i*2;
        else
            t=i; 
        //如果他有右兒子的情況下,再對(duì)右兒子進(jìn)行討論 
        if(i*2+1 <= n)
        {
            //如果右兒子的值更小,更新較小的結(jié)點(diǎn)編號(hào)  
            if(A[t] > A[i*2+1])
                t=i*2+1;
        }
        //如果發(fā)現(xiàn)最小的結(jié)點(diǎn)編號(hào)不是自己,說(shuō)明子結(jié)點(diǎn)中有比父結(jié)點(diǎn)更小的  
        if(t!=i)
        {
            swap(A, t, i);//交換
            i=t;//更新i為剛才與它交換的兒子結(jié)點(diǎn)的編號(hào),便于接下來(lái)繼續(xù)向下調(diào)整
            count++;
            printf("\n\n第 %d 次調(diào)整堆:\n", count);
            char filename[10];
            sprintf(filename, "heap%d.dot", count);
            printHeap(A, filename, 17);
        }
        else
            flag=1;//則否說(shuō)明當(dāng)前的父結(jié)點(diǎn)已經(jīng)比兩個(gè)子結(jié)點(diǎn)都要小了,不需要在進(jìn)行調(diào)整了,退出
    }
}

int main(){
    int A[N+1] = { 0, 2, 7, 24, 11, 67, 35, 25, 16, 19, 97, 80, 50}; // 這里為了直接展示調(diào)整堆算法,直接給出已經(jīng)建好堆的數(shù)組,免去建堆這一步,A[0]是不使用的,堆從A[1]開(kāi)始。
    printf("初始化堆:\n");
    printHeap(A, "heap.dot", 0);
    A[1] = 17; // 測(cè)試,修改堆頂值
    printf("\n\n修改堆頂值為17:\n");
    printHeap(A, "heap0.dot", 17);
    godown(A, N, 1);
    return 0;
}

編譯gcc heap.c -o heap
然后執(zhí)行./heap
可以看到同之前一樣也在打印出堆,不過(guò)這次多生成了一些東西,在當(dāng)前目錄下發(fā)現(xiàn)了heap.dot、heap0.dot、heap1.dot、heap2.dot、heap3.dot幾個(gè)文件,然后在當(dāng)前目錄下寫(xiě)一個(gè)腳本dot.sh,編輯腳本,內(nèi)容如下

#!/bin/sh
dot -Tpng heap.dot -o heap.png
dot -Tpng heap0.dot -o heap0.png
dot -Tpng heap1.dot -o heap1.png
dot -Tpng heap2.dot -o heap2.png
dot -Tpng heap3.dot -o heap3.png

dot是graphviz的命令,記得要把這個(gè)燃盡安裝上哦。
然后,執(zhí)行腳本./dot.sh
然后就發(fā)現(xiàn)生成了heap.png、heap0.png、heap1.png、heap2.png、heap3.png,分別是上面終端打印出幾種形態(tài)的圖片版本,例如


初始堆

堆頂換成17

堆頂下移到左孩子

17再下移到左孩子

17再下移到左孩子

始于2016-06-08,杭州;更新至2016-06-12,杭州。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容

  • Android 自定義View的各種姿勢(shì)1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 173,466評(píng)論 25 708
  • 第三天學(xué)習(xí)成果如下: 今天是臨寫(xiě)九成宮的第三天,開(kāi)始之前,內(nèi)心萬(wàn)感疲憊,心想今天就算了吧,明天再臨。。。但過(guò)了不久...
    壓不彎的稻草閱讀 270評(píng)論 0 0
  • ?心享事成 ?今日心享~享受做愛(ài) 做愛(ài),是身體層面最大的喜悅! 一次做愛(ài),對(duì)生命都是一種升華! 做愛(ài),并不等于性;...
    axjl如意閱讀 2,316評(píng)論 0 0
  • 社會(huì)的形態(tài)日新月異,各色各樣...
    余生丶須盡歡閱讀 413評(píng)論 0 1
  • 本章節(jié)列出了小提琴家帕格尼尼,莫扎特,滑冰拉廖,天才跳高運(yùn)動(dòng)員,這些人都在不同的時(shí)代,作者不熟悉他們,我們也...
    yclhub閱讀 1,574評(píng)論 0 0