⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 draw-tree.c

📁 伸展树
💻 C
字号:
/* Draws ascii picture of a tree.  Allows the user to splay */
/* any node, and then redraws the tree.                     */
/* written by Daniel Sleator <sleator@cs.cmu.edu>           */
/* The following program is in the public domain.           */


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


#define TRUE 1
#define FALSE 0
int size;


/* 
 * This version of top-down-simple splay maintains parent pointers.
 */
typedef struct tree_node {
    struct tree_node * left, * right, * parent;
    int key;
} Tree;

#define set_parent_left(t) {if((t)->left != NULL) (t)->left->parent = (t);}
#define set_parent_right(t) {if((t)->right != NULL) (t)->right->parent = (t);}

Tree * splay (int i, Tree * t) {
    Tree N, *l, *r, *y;
    if (t == NULL) return t;
    N.left = N.right = NULL;
    l = r = &N;

    for (;;) {
	if (i < t->key) {
	    if (t->left == NULL) break;
	    if (i < t->left->key) {
		y = t->left;                           /* rotate right */
		t->left = y->right;
		if (t->left != NULL) t->left->parent = t;
		y->right = t;
		t->parent = y;
		t = y;
		if (t->left == NULL) break;
	    }
	    r->left = t;                               /* link right */
	    t->parent = r;
	    r = t;
	    t = t->left;
	} else if (i > t->key) {
	    if (t->right == NULL) break;
	    if (i > t->right->key) {
		y = t->right;                          /* rotate left */
		t->right = y->left;
		if (t->right != NULL) t->right->parent = t;
		y->left = t;
		t->parent = y;
		t = y;
		if (t->right == NULL) break;
	    }
	    l->right = t;                              /* link left */
	    t->parent = l;
	    l = t;
	    t = t->right;
	} else {
	    break;
	}
    }
    l->right = t->left;                                /* assemble */
    if (l->right != NULL) l->right->parent = l;
    r->left = t->right;
    if (r->left != NULL) r->left->parent = r;
    t->left = N.right;
    if (t->left != NULL) t->left->parent = t;
    t->right = N.left;
    if (t->right != NULL) t->right->parent = t;
    t->parent = NULL;
    return t;
}

Tree * move_to_root (int i, Tree * t) {
    Tree N, *l, *r, *y;
    if (t == NULL) return t;
    N.left = N.right = NULL;
    l = r = &N;

    for (;;) {
	if (i < t->key) {
	    if (t->left == NULL) break;
	    r->left = t;                               /* link right */
	    t->parent = r;
	    r = t;
	    t = t->left;
	} else if (i > t->key) {
	    if (t->right == NULL) break;
	    l->right = t;                              /* link left */
	    t->parent = l;
	    l = t;
	    t = t->right;
	} else {
	    break;
	}
    }
    l->right = t->left;                                /* assemble */
    if (l->right != NULL) l->right->parent = l;
    r->left = t->right;
    if (r->left != NULL) r->left->parent = r;
    t->left = N.right;
    if (t->left != NULL) t->left->parent = t;
    t->right = N.left;
    if (t->right != NULL) t->right->parent = t;
    t->parent = NULL;
    return t;
}

int check_tree(Tree * t) {
    if (t == NULL) return TRUE;
    if (t->left != NULL &&(t->left->parent != t || !check_tree(t->left))) {
	return FALSE;
    }
    if (t->right != NULL && (t->right->parent != t || !check_tree(t->right))) {
	return FALSE;
    }
    return TRUE;
}

#define INFINITY (1<<20)
#define LABLEN 20

int min (int X, int Y)  {return ((X) < (Y)) ? (X) : (Y);}
int max (int X, int Y)  {return ((X) > (Y)) ? (X) : (Y);}

typedef struct pnode_struct Pnode;

struct pnode_struct {
    Pnode * left, * right;
    int edge_length; /* length of the edge from this node to its children */
                     /* number of "\" or "/".  so it's at least 1         */
                     /* unless both children are null.  Then it's 0       */
    
    int height;      /* The number of rows required to print this tree */
    int lablen;
    int parent_dir;       /* -1=I am left, 0=I am root, 1=right       */
                          /* this is used to decide how to break ties */
                          /* when the label is of even length         */
    char label[LABLEN+1];
};

int allocs_in_use;
void my_free(void * p) {
    allocs_in_use--;
    free(p);
}
void * my_alloc(int size) {
    void * p = malloc(size);
    allocs_in_use++;
    if (p == NULL) {
        fprintf(stderr, "Ran out of space.  Requested size=%d.\n", size);
        exit(1);
    }
    return p;
}

/* Free all the nodes of the given tree */
void free_ptree(Pnode *pn) {
    if (pn == NULL) return;
    free_ptree(pn->left);
    free_ptree(pn->right);
    my_free(pn);
}

Pnode * build_ptree_rec(Tree * t) {
    Pnode * pn;
    if (t == NULL) return NULL;
    pn = my_alloc(sizeof(Pnode));
    pn->left = build_ptree_rec(t->left);
    pn->right = build_ptree_rec(t->right);
    if (pn->left != NULL) pn->left->parent_dir = -1;
    if (pn->right != NULL) pn->right->parent_dir = 1;

    sprintf(pn->label, "%d", t->key);
    pn->lablen = strlen(pn->label);
    return pn;
}

/*
 * Copy the tree from the original structure into the Pnode structure
 * fill in the parent_dir, label, and labelen fields, but not the    
 * edge_length or height fields.                                     
 */
Pnode * build_ptree(Tree * t) {
    Pnode *pn;
    if (t == NULL) return NULL;
    pn = build_ptree_rec(t);
    pn->parent_dir = 0;
    return pn;
}

/* 
 * The lprofile array is description of the left profile of a tree.
 * Assuming the root is located at (0,0), lprofile[i] is the leftmost
 * point used on row i of the tree.  rprofile is similarly defined.
 */
#define MAX_HEIGHT 1000
int lprofile[MAX_HEIGHT];
int rprofile[MAX_HEIGHT];

/*
 * The following function fills in the lprofile array for the given tree.
 * It assumes that the center of the label of the root of this tree
 * is located at a position (x,y).  It assumes that the edge_length
 * fields have been computed for this tree.
 */
void compute_lprofile(Pnode *pn, int x, int y) {
    int i, isleft;
    if (pn == NULL) return;
    isleft = (pn->parent_dir == -1);
    lprofile[y] = min(lprofile[y], x-((pn->lablen-isleft)/2));
    if (pn->left != NULL) {
	for (i=1; i <= pn->edge_length && y+i < MAX_HEIGHT; i++) {
	    lprofile[y+i] = min(lprofile[y+i], x-i);
	}
    }
    compute_lprofile(pn->left, x-pn->edge_length-1, y+pn->edge_length+1);
    compute_lprofile(pn->right, x+pn->edge_length+1, y+pn->edge_length+1);
}
void compute_rprofile(Pnode *pn, int x, int y) {
    int i, notleft;
    if (pn == NULL) return;
    notleft = (pn->parent_dir != -1);
    rprofile[y] = max(rprofile[y], x+((pn->lablen-notleft)/2));
    if (pn->right != NULL) {
	for (i=1; i <= pn->edge_length && y+i < MAX_HEIGHT; i++) {
	    rprofile[y+i] = max(rprofile[y+i], x+i);
	}
    }
    compute_rprofile(pn->left, x-pn->edge_length-1, y+pn->edge_length+1);
    compute_rprofile(pn->right, x+pn->edge_length+1, y+pn->edge_length+1);
}

/* 
 * This function fills in the edge_length and height fields of the
 * specified tree.
 */
void compute_edge_lengths(Pnode *pn) {
    int h, hmin, i, delta;
    if (pn == NULL) return;
    compute_edge_lengths(pn->left);
    compute_edge_lengths(pn->right);

    /* first fill in the edge_length of pn */
    if (pn->right == NULL && pn->left == NULL) {
	pn->edge_length = 0;
    } else {
	if (pn->left != NULL) {
	    for (i=0; i<pn->left->height && i < MAX_HEIGHT; i++) {
		rprofile[i] = -INFINITY;
	    }
	    compute_rprofile(pn->left, 0, 0);
	    hmin = pn->left->height;
	} else {
	    hmin = 0;
	}
	if (pn->right != NULL) {
	    for (i=0; i<pn->right->height && i < MAX_HEIGHT; i++) {
		lprofile[i] = INFINITY;
	    }
	    compute_lprofile(pn->right, 0, 0);
	    hmin = min(pn->right->height, hmin);
	} else {
	    hmin = 0;
	}
	delta = 4;
	for (i=0; i<hmin; i++) {
	    delta = max(delta, 2 + 1 + rprofile[i] - lprofile[i]);
       /* the "2" guarantees a gap of 2 between different parts of the tree */
	}
	/* If the node has two children of height 1, then we allow the
           two leaves to be within 1, instead of 2 */
	if (((pn->left != NULL && pn->left->height == 1) ||
	    (pn->right != NULL && pn->right->height == 1))&&delta>4) delta--;
	pn->edge_length = ((delta+1)/2) - 1;
    }

    /* now fill in the height of pn */
    h = 1;
    if (pn->left != NULL) {
	h = max(pn->left->height + pn->edge_length + 1, h);
    }
    if (pn->right != NULL) {
	h = max(pn->right->height + pn->edge_length + 1, h);
    }
    pn->height = h;
}

int print_next;  /* used by print_level.  If you call "printf()" at   */
                 /* any point, this is the x coordinate of the next   */
                 /* char printed.                                     */

/*
 * This function prints the given level of the given tree, assuming
 * that the node pn has the given x cordinate.
 */
void print_level(Pnode *pn, int x, int level) {
    int i, isleft;
    if (pn == NULL) return;
    isleft = (pn->parent_dir == -1);
    if (level == 0) {
	for (i=0; i<(x-print_next-((pn->lablen-isleft)/2)); i++) {
	    printf(" ");
	}
	print_next += i;
	printf("%s", pn->label);
	print_next += pn->lablen;
    } else if (pn->edge_length >= level) {
	if (pn->left != NULL) {
	    for (i=0; i<(x-print_next-(level)); i++) {
		printf(" ");
	    }
	    print_next += i;
	    printf("/");
	    print_next++;
	}
	if (pn->right != NULL) {
	    for (i=0; i<(x-print_next+(level)); i++) {
		printf(" ");
	    }
	    print_next += i;
	    printf("\\");
	    print_next++;
	}
    } else {
	print_level(pn->left, x-pn->edge_length-1, level-pn->edge_length-1);
	print_level(pn->right, x+pn->edge_length+1, level-pn->edge_length-1);
    }
}

/* 
 * This pretty-prints the given tree, left-justified.
 * The tree is drawn in such a way that both of the edges down from
 * a node are the same length.  This length is the minimum such that
 * the two subtrees are separated by at least two blanks.
 */
void pretty_print_tree(Tree * t) {
    Pnode *proot;
    int xmin, i;
    if (t == NULL) return;
    proot = build_ptree(t);
    compute_edge_lengths(proot);
    for (i=0; i<proot->height && i < MAX_HEIGHT; i++) {
	lprofile[i] = INFINITY;
    }
    compute_lprofile(proot, 0, 0);
    xmin = 0;
    for (i = 0; i < proot->height && i < MAX_HEIGHT; i++) {
	xmin = min(xmin, lprofile[i]);
    }
    for (i = 0; i < proot->height; i++) {
	print_next = 0;
	print_level(proot, -xmin, i);
	printf("\n");
    }
    if (proot->height >= MAX_HEIGHT) {
	printf("(This tree is taller than %d, and may be drawn incorrectly.)\n", MAX_HEIGHT);
    }
    free_ptree(proot); 
}

Tree * insert(int i, Tree * t) {
/* Insert i into the tree t, unless it's already there.    */
/* Return a pointer to the resulting tree.                 */
    Tree * new;
    
    new = (Tree *) my_alloc (sizeof (Tree));
    new->key = i;
    if (t == NULL) {
	new->left = new->right = new->parent = NULL;
	size = 1;
	return new;
    }
    t = splay(i,t);
    if (i < t->key) {
	new->left = t->left;
	new->right = t;
	t->left = NULL;
	set_parent_left(new);
	set_parent_right(new);
	size ++;
	return new;
    } else if (i > t->key) {
	new->right = t->right;
	new->left = t;
	t->right = NULL;
	set_parent_left(new);
	set_parent_right(new);
	size++;
	return new;
    } else { /* We get here if it's already in the tree */
             /* Don't add it again                      */
	my_free(new);
	return t;
    }
}

Tree * delete(int i, Tree * t) {
/* Deletes i from the tree if it's there.               */
/* Return a pointer to the resulting tree.              */
    Tree * x;
    if (t==NULL) return NULL;
    t = splay(i,t);
    if (i == t->key) {               /* found it */
	if (t->left == NULL) {
	    x = t->right;
	} else {
	    x = splay(i, t->left);
	    x->right = t->right;
	    set_parent_right(x);
	}
	size--;
	my_free(t);
	return x;
    }
    return t;                         /* It wasn't there */
}

void main() {
    Tree * root;
    char line[100];
    int i, N;
    root = NULL;              /* the empty tree */
    size = 0;
    while(TRUE) {
	printf("Enter the number of nodes in the tree: ");
	N = -1;
	if (fgets(line, sizeof(line), stdin) == NULL) exit(1);
	sscanf(line,"%d", &N);
	if ((N<1) || (N > 200)) {
	    printf("Choose a number between 1 and 200.\n");
	    continue;
	}
	break;
    }

    for (i = 0; i < N; i++) {
	root = insert(i, root);
	if (!check_tree(root)) printf("error\n");;
    }
    pretty_print_tree(root);
    for (;;) {
	printf("Select a node to splay: ");
	if (fgets(line, sizeof(line), stdin) == NULL) break;
	if ((sscanf(line, "%d", &i) == 1) && (i >= 0 && i < N)) {
	    /*	root = move_to_root(i, root);  */
	    root = splay(i, root);
	} else {
	    if (strncasecmp(line, "quit", strlen("quit")) == 0) {
		break;
	    } else {
		printf("Choose a number in [%d, %d] or type \"quit\".\n", 0, N-1);
		continue;
	    }
	}
	pretty_print_tree(root);
    }
/*
    for (i = 0; i < N; i++) {
	root = delete((541*i) & (N-1), root);
	if (!check_tree(root)) printf("error\n");;
    }
    printf("size = %d\n", size);
*/
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -