二叉树插入的动画GIF

时间:2014-02-23 10:39:12

标签: c dot imagemagick-convert

我正在尝试使用ubuntu的dotconvert实用程序生成简单二叉树插入的GIF动画。但它并不是我想要的完全正常工作。我在最后得到的动画gif没有显示完整的树,只显示了根节点。

要测试程序,只需输入一些随机整数并用-1停止输入部分。

#include<stdio.h>
#include<stdlib.h>

struct node{
    int value;
    struct node *left,*right;
};

typedef struct node node;

node *root;
FILE *out;

node *insert(node *,int);
node *new_node(int);

int main()
{
    root = NULL;

    int temp;
    int k = 0;

    while(1)
    {
        scanf("%d",&temp);
        if( temp == -1) break;

        root = insert(root,temp);

        take_snap(k++); // this function writes the dot file and create a jpg image for the current tree
    }

    animate();
    // this function use convert utility to combine all the images made earlier and create a animated gif
    return 0;
}

node *new_node(int x)
{
    node *new = (node *) malloc(sizeof(node));
    new->left = new->right = NULL;
    new->value = x;
    return new;
}

node *insert(node *s,int temp)
{
    if( s == NULL)
        return new_node(temp);
    else if( s->value < temp )
        s->right = insert(s->right,temp);
    else if( s->value > temp )
        s->left = insert(s->left,temp);
    return s;
}

take_snap(int index)
{
    out = fopen("temp.dot","w");
    fprintf(out,"graph {\n");
    if( root )
        fprintf(out,"%d\n",root->value);
    dottify(root);
    fprintf(out,"}\n");

    fclose(out);
    char tempstr[100];
    sprintf(tempstr,"dot -Tjpg temp.dot -o image%d.jpg",index);
    system(tempstr);
}

dottify(node *s)
{
    if( s )
    {
        if(s->left)
        {
            fprintf(out,"%d -- %d\n",s->value,(s->left)->value);
            dottify(s->left);
        }

        if(s->right)
        {
            fprintf(out,"%d -- %d\n",s->value, (s->right)->value);
            dottify(s->right);
        }
    }
}


animate()
{
    //system("convert *.jpg -resize 200x200 *.jpg");
    system("convert -delay 100 -loop 0 image*.jpg animation.gif");
    system("eog ./animation.gif");
}

我做错了什么?

我尝试使用resize运算符,但我没有得到我想要的结果。

http://i.stack.imgur.com/e1rPD.gif image

编辑:

我已经注释掉了调整大小部分,不知怎的,它正在制作超过必要的jpgs.But问题仍然存在。

3 个答案:

答案 0 :(得分:6)

convert *.jpg -resize 200x200 *.jpg存在两个问题:

  • 您需要添加感叹号以强制convert混乱宽高比
  • convert无法进行批量转化,一次只能进行一次图片处理。

像这样:

for i in *.jpg ; do convert $i -resize 200x200! $i ; done

但由于缩放,结果不会很好。

您可以做的另一件事是强制graphviz生成固定大小的图片,只需添加一些图形属性:ratio=fill, size="2,2!", resolution=100

像这样:

take_snap(int index)
{
    out = fopen("temp.dot","w");
    fprintf(out,"graph {\n");
    fprintf(out,"graph [ratio=fill, size=\"2,2!\", resolution=100];\n");

问题是所有图像的大小都是200x200px,但单节点图形除外 我不知道为什么会这样。但您可以使用convert修复此图片。

convert image0.jpg -resize 200x200! image0.jpg

结果如下:
enter image description here

答案 1 :(得分:4)

这是我对此的看法:将整个树构建到内存中,然后为每个附加节点输出整个.dot文件,但将“尚未添加”节点的属性设置为“不可见” 。由于现在所有树的大小都相同,因此不需要调整单个文件的大小。

为此,'创建索引'也需要存储到节点中。请注意,我将输出文件格式更改为“GIF” - 正如您所看到的,将简单图像作为JPEG存储会引入难看的伪像。

再次使用整个代码(抱歉,整体上有很多小改动):

#include <stdio.h>
#include <stdlib.h>

struct node {
    int value;
    int index;
    struct node *left,*right;
};

typedef struct node node;

node *root;
FILE *out;

node *insert(node *,int,int);
node *new_node(int,int);

int main()
{
    root = NULL;

    int temp;
    int k = 0, i;

    while(1)
    {
        scanf("%d",&temp);
        if( temp == -1) break;

        root = insert(root,temp, k);
        k++;
    }

    for (i=0; i<k; i++)
    {
        take_snap (i);
    }

    // this function use convert utility to combine all the images made earlier and create a animated gif
    animate();
    return 0;
}

node *new_node (int x, int index)
{
    node *new = (node *) malloc(sizeof(node));
    new->left = new->right = NULL;
    new->value = x;
    new->index = index;

    return new;
}

node *insert(node *s,int temp, int index)
{
    if( s == NULL)
        return new_node(temp, index);
    else if( s->value < temp )
        s->right = insert(s->right,temp, index);
    else if( s->value > temp )
        s->left = insert(s->left,temp, index);
    return s;
}

take_snap (int index)
{
    char tempstr[100];
    sprintf (tempstr, "temp%d.dot", index);
    out = fopen(tempstr,"w");

    fprintf(out,"graph {\n");
    if( root )
    {
        fprintf(out,"%d\n",root->value);
        dottify(root, index);
    }
    fprintf(out,"}\n");

    fclose(out);

    sprintf(tempstr,"dot -Tgif temp%d.dot -o image%d.gif",index,index);
    system(tempstr);
}

dottify(node *s, int index)
{
    if( s )
    {
        if(s->left)
        {
            if (s->left->index <= index)
                fprintf(out,"%d -- %d\n",s->value,s->left->value);
            else
            {
                fprintf(out,"%d [style=invis]\n", s->left->value);
                fprintf(out,"%d -- %d [style=invis]\n", s->value, s->left->value);
            }
            dottify(s->left, index);
        }

        if(s->right)
        {
            if (s->right->index <= index)
                fprintf(out,"%d -- %d\n",s->value, s->right->value);
            else
            {
                fprintf(out,"%d [style=invis]\n", s->right->value);
                fprintf(out,"%d -- %d [style=invis]\n", s->value, s->right->value);
            }
            dottify(s->right, index);
        }
    }
}


animate()
{
    //system("convert *.jpg -resize 200x200 *.jpg");
    system("convert -delay 100 -loop 0 image*.jpg animation.gif");
    system("eog ./animation.gif");
}

这就是它使用相同输入max taldykin的样子:3 1 6 2 8 4 5 0 -2 -1

animation of binary tree insertion

[编辑]哦,让我们有一些有趣的颜色。添加此

if (s->left->index == index)
    fprintf(out,"%d [style=filled, color=cyan]\n", s->left->value);

right->value进入dottify例程的相同内容:

animation of colored insertions

答案 2 :(得分:0)

这是Java中的二进制树代码。

它具有插入PREORDER POSTORDER的所有功能 它有动画的二进制树和它的镜像。它也通过动画搜索功能。 如果您有任何疑问,请与我联系。

package classassignmentalgo;

import java.awt.*;
import java.awt.event.*;
import java.io.IOException;
import java.util.*;
import javax.swing.*;
// * @author gauraangkhurana

public class ClassAssignmentAlgo extends JFrame implements ActionListener{

// Adding all panels, text boxes and labels here.
JPanel panel1 = new JPanel(new GridLayout(0,2));
JPanel panel2 = new JPanel(new GridLayout(0,2));
JTextField txtBox = new JTextField();
static JLabel lbl1 = new JLabel();
static JLabel lbl2 = new JLabel();
static JLabel lbl3 = new JLabel();
static JLabel lbl4 = new JLabel();
static JLabel lbl5 = new JLabel();
static JLabel lblExtra = new JLabel();
static String preorder = new String();
static String inorder = new String();
static String postorder = new String();


// Adding all buttons here 
JButton btnTree = new JButton("Tree");
JButton btnPreorder = new JButton(("Preorder"));
JButton btnInorder = new JButton("Inorder");
JButton btnPostorder = new JButton("postorder");
JButton btnLeafNodes = new JButton("Leaf Nodes");
JButton btnNonLeaf = new JButton("Non- leaf nodes");
JButton btnMirror = new JButton("Mirror");
JButton btnSearch = new JButton("Search");
JTextField txtSearch = new JTextField();
static int[][] coordinateArray;


  //Constructor to add all panels and buttons to frame.
  public ClassAssignmentAlgo(){
    panel2.add(btnTree);
    panel2.add(txtBox);
    panel2.add(btnPreorder);
    panel2.add(lbl1);
    panel2.add(btnInorder);
    panel2.add(lbl2);
    panel2.add(btnPostorder);
    panel2.add(lbl3);
    panel2.add(btnLeafNodes);
    panel2.add(lbl4);
    panel2.add(btnNonLeaf);
    panel2.add(lbl5);
    panel2.add(btnMirror);
    panel2.add(lblExtra);
    panel2.add(btnSearch);
    panel2.add(txtSearch);
    getContentPane().setLayout(new GridLayout(2,0));
    add(panel1);
    add(panel2);
    // Adding methods to all buttons.
    btnTree.addActionListener(this);
    btnPreorder.addActionListener(this);
    btnInorder.addActionListener(this);
    btnPostorder.addActionListener(this);
    btnLeafNodes.addActionListener(this);
    btnNonLeaf.addActionListener(this);
    btnMirror.addActionListener(this);
    btnSearch.addActionListener(this);
}


public static void main(String[] args) {

    JFrame frame = new ClassAssignmentAlgo();
    frame.setSize(900,700);
    frame.setVisible(true);
    frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
}




@Override
public void actionPerformed(ActionEvent e) {
    // When Button Tree is pressed 
    if(e.getSource() == btnTree){
        String input = txtBox.getText();
        insertInBtree(input,8);
    }
    //When button preorder is pressed.
    if(e.getSource() == btnPreorder){
        String input = txtBox.getText();
        insertInBtree(input,0);
    }
    //When button postorder is pressed.
    if(e.getSource() == btnPostorder){
        String input = txtBox.getText();
        insertInBtree(input,2);
    }
    //When button inorder is pressed.
    if(e.getSource() == btnInorder){
        String input = txtBox.getText();
        insertInBtree(input,1);
    }
    //When button leaf nodes is pressed.
    if(e.getSource() == btnLeafNodes){
        String input = txtBox.getText();
        insertInBtree(input,4);
    }
    //When button non leaf nodes is pressed.
    if(e.getSource() == btnNonLeaf){
        String input = txtBox.getText();
        insertInBtree(input,5);
    }
    //When button button mirror is pressed.
    if(e.getSource() == btnMirror){
        String input = txtBox.getText();
        insertInBtree(input,3);
    }
    //When button search is pressed.
    if(e.getSource() == btnSearch){
        String input = txtBox.getText();
        insertInBtree(input,6);
    }

}

public  void insertInBtree(String a,int b){
    BTree instance = new BTree();
    instance.imp(a,b);
}

  // BTREE Class which is a subclass of the main class.  
    public  class BTree {

BTree root = null;
BTree temp1;
BTree temp2;
int data;
BTree right,left;
 int[] array = new int[20];

 // Constructor to add empty Btree.
public BTree(){
right = null;
left = null;
data = 0;
}

//Constructor to add Btree with some data. 
public BTree(int n){
    data = n;
    right = null;
    left = null;
  }

//This string is to print the output when postorder, preorder or inorder button is pressed.
String print = new String();

//This function adds the input to the Btree.
 void imp(String received,int a) {
   try{
     String[] array = received.split(",");
     coordinateArray = new int[array.length][2];
     for(int i=0;i<array.length;i++){
        InBTree(Integer.parseInt(array[i]));
     }  
   }
   //If the input entered is in wrong format.
     catch(Exception e){
     JOptionPane.showMessageDialog(null,"Wrong Input");
     System.exit(0);
     }

     temp1 = root;
     temp2 = root;

     switch(a){
         // Switch case for the buttons pressed.
         case 0 : preorderOfBtree(root);
           break;

         case 1 : inorderOfBtree(root);
           break;

         case 2 : postorderOfBtree(root);
           break;

         case 3 :mirrorImageOfBtree(temp2);
                 printMirror(temp2);
          break;

         case 4: leafNodesOfBtree(root);
             break;
         case 5 : nonleafNodesOfBtree(root);
             break;

         case 6 : searchInBtree(root);
             break;

         case 8 : drawingBtree(root,180);
             break;
         default: 
             break;

  }
 }
 int a = 40;
 int radiusOfNode = 20;
 int gapHeight = 50;

   // When search button is pressed.  
   void searchInBtree(BTree node){
   Graphics g = getGraphics();
   displayInPanel(g,node,180,80,80);
   if(flag == 0){
       JOptionPane.showMessageDialog(null,"Element not found");
   }
  }
   //This function is called when the Tree button is pressed.    
  void drawingBtree(BTree node,int a){
    drawBtree(node,a);
  }    

    void drawBtree(BTree node,int startingPoint){
   Graphics g = getGraphics();
     if(node != null){
         displayTreeInorderMirror(g,node,startingPoint,80,80);

  }

  }
 int flag = 0;

 //To Draw BTree in normal order.
  void displayInPanel(Graphics f, BTree node,int xCoordinates,int yCoordinates,int gapWidth){

     String s = txtSearch.getText();
     int sInt = Integer.parseInt(s);
     if(sInt == node.data){
         f.setColor(Color.green);
         flag = 1;
     }
     else{
         if(flag ==0){
             f.fillOval(xCoordinates-radiusOfNode, yCoordinates-radiusOfNode, 2*radiusOfNode,   2*radiusOfNode);
             f.setColor(Color.red);
         }
         else{
             f.drawOval(xCoordinates-radiusOfNode, yCoordinates-radiusOfNode, 2*radiusOfNode, 2*radiusOfNode);
             f.setColor(Color.lightGray);
         }
     }

     f.drawString(String.valueOf(node.data), xCoordinates-6, yCoordinates+4);
     f.setColor(Color.black);

     if(node.left!=null){
         drawLeftLine(f,xCoordinates-gapWidth,yCoordinates+gapHeight,xCoordinates,yCoordinates);
         displayInPanel(f,node.left,xCoordinates-gapWidth,yCoordinates+gapHeight,gapWidth/2);
     }

     if(node.right!=null){
         drawRightLine(f,xCoordinates+gapWidth,yCoordinates+gapHeight,xCoordinates,yCoordinates);
         displayInPanel(f,node.right,xCoordinates+gapWidth,yCoordinates+gapHeight,gapWidth/2);
     }

  }

 //This function is called to print the mirror image of the btree.


 void printMirror(BTree temporary){
    drawingBtree(temporary,650);
 }
 //this function is used to display the mirror image  of the btree
 void displayTreeInorderMirror(Graphics f, BTree node,int xCoordinates,int yCoordinates,int   gapWidth){
     f.fillOval(xCoordinates-radiusOfNode, yCoordinates-radiusOfNode, 2*radiusOfNode, 2*radiusOfNode);
     f.setColor(Color.LIGHT_GRAY);
     f.drawString(String.valueOf(node.data), xCoordinates-6, yCoordinates+4);
     f.setColor(Color.BLACK);
     if(node.left!=null){
         drawLeftLine(f,xCoordinates-gapWidth,yCoordinates+gapHeight,xCoordinates,yCoordinates);
         displayTreeInorderMirror(f,node.left,xCoordinates-gapWidth,yCoordinates+gapHeight,gapWidth/2);
     }

     if(node.right!=null){
         drawRightLine(f,xCoordinates+gapWidth,yCoordinates+gapHeight,xCoordinates,yCoordinates);
         displayTreeInorderMirror(f,node.right,xCoordinates+gapWidth,yCoordinates+gapHeight,gapWidth/2);
     }

 }

 //this function draws the left line extending from the node

 void drawLeftLine(Graphics f,int coordinateX,int coordinateY,int coordinateX2,int coordinateY2){

     double d = Math.sqrt(gapHeight*gapHeight+(coordinateX2-coordinateX)*(coordinateX2-coordinateX));
     int startingX = (int)(coordinateX+radiusOfNode*(coordinateX2-coordinateX)/d);
     int startingY = (int)(coordinateY-radiusOfNode * gapHeight/d);
     int endingX = (int)(coordinateX2 - radiusOfNode * (coordinateX2-coordinateX)/d);
     int endingY = (int)(coordinateY2+radiusOfNode * gapHeight /d);
    try {
        Thread.sleep(600);
    } catch (InterruptedException ex) {
    }
     f.drawLine(startingX,startingY,endingX,endingY);
 }

 //this function draws the right line extending from the node
 void drawRightLine(Graphics f,int coordinateX,int coordinateY,int coordinateX2,int coordinateY2){
      double d = Math.sqrt(gapHeight*gapHeight+(coordinateX2-coordinateX)*(coordinateX2-coordinateX));
     int startingX = (int)(coordinateX-radiusOfNode*(coordinateX-coordinateX2)/d);
     int startingY = (int)(coordinateY-radiusOfNode * gapHeight/d);
     int endingX = (int)(coordinateX2 - radiusOfNode * (coordinateX-coordinateX2)/d);
     int endingY = (int)(coordinateY2+radiusOfNode * gapHeight /d);
     try {
        Thread.sleep(600);
    } catch (InterruptedException ex) {
    }
     f.drawLine(startingX,startingY,endingX+5,endingY-8);
 }


void InBTree(int n){
    root = insertInBtree(root,n);

}

//Function to insert elements the elements in the btree.

BTree insertInBtree(BTree node,int da){
    if(node == null ){
        node = new BTree(da);
    }
    else{
        if(node.data > da){
            node.left = insertInBtree(node.left,da);
        }
        else{
           node.right = insertInBtree(node.right,da);
        }
    }
    return node;
  }
    //Preorder tranversal of btree
void preorderOfBtree(BTree r)
 {
     if (r != null)
     {
         print += r.data +"      ";
         preorderOfBtree(r.left);       
         preorderOfBtree(r.right);

     }
     lbl1.setText(print);
 }

//To print the  leaf nodes of the btree.
void leafNodesOfBtree(BTree r){

    if(r == null){
        return;
    }
    if(r.left!=null || r.right!=null){
        leafNodesOfBtree(r.left);
        leafNodesOfBtree(r.right); 
    }
    else{
        print += r.data+"      ";
    }

    lbl4.setText(print);
}


//to print leaf nodes
void nonleafNodesOfBtree(BTree r){
    if(r==null){
        return;
    }
    if(r.left ==null && r.right == null){
        return;
    }
    else{
        nonleafNodesOfBtree(r.left);
        nonleafNodesOfBtree(r.right);
        print += r.data+"      ";
    }
    lbl5.setText(print);
  }

void postorderOfBtree(BTree r){
 if(r!=null){
     postorderOfBtree(r.left);
     postorderOfBtree(r.right);
     print += r.data+"      ";
 }
          lbl3.setText(print);

}
//inorder traversal of the btree
 void inorderOfBtree(BTree r){
 if(r != null){
     inorderOfBtree(r.left);
     print += r.data+"      ";
     inorderOfBtree(r.right);
   }
          lbl2.setText(print);

   }



 //This function creates a mirror image of the Btree.
   BTree mirrorImageOfBtree(BTree n){
    if(n == null){
     return null;
    }
    else{
     BTree tree =  new BTree();
      mirrorImageOfBtree(n.left);
      mirrorImageOfBtree(n.right);

      tree = n.left;
      n.left = n.right;
      n.right = tree;
    }
   return n;
   }
   }
   }