天天看點

二叉樹(tree)一、二叉樹的周遊二、二叉樹程式

目錄

一、二叉樹的周遊

二、二叉樹程式

1.建立結構體

2.插入結點

 2.找到某個結點,并傳回結點中的資料

3.左偏 周遊輸出

4.平衡二叉樹

5.周遊

1)先序周遊

2)中序周遊

3)後序周遊

4)按層周遊

6.删除結點

一、二叉樹的周遊

二叉樹(tree)一、二叉樹的周遊二、二叉樹程式

1.先序周遊        (根結點---左結點---右結點)

        A-B-D-E-G-C-F-F-I

2.中序周遊        (左節點---根結點---右節點)

        D-B-G-E-A-C-H-F-I

3.後續周遊        (左結點---右節點---根結點)

        D-G-E-B-H-I-F-C-A

二、二叉樹程式

1.建立結構體

struct score_st
{
	int id;
	char name[NAMESIZE];
	int math;
};
struct node_st
{
	struct score_st data;
	struct node_st *l,*r;
};
           

2.插入結點

二叉樹(tree)一、二叉樹的周遊二、二叉樹程式
int insert(struct node_st **root, struct score_st *data)
{
	struct node_st *node;

	if(*root == NULL)     //當root指向的指針為空
	{
		node = malloc(sizeof(*node));    //建立一個結點
		if(node == NULL)
			return -1;
		node->data = *data;            //将要插入的資料指派給node
		node->l = node->r = NULL;       //結點的做指針和右指針設為NULL
		*root = node;                  //将結點的位址儲存到root指向的指針中
		return 0;
	}

	if(data->id <=  (*root)->data.id)    //當樹不為空時,比較id的值,id小的在樹的左側
		return insert(&(*root)->l,data);
	return insert(&(*root)->r,data);    //id大的在樹的右側
}
           

 2.找到某個結點,并傳回結點中的資料

struct score_st *find(struct node_st *root, int id)
{
	if(root == NULL)    
		return NULL;
	if(root->data.id == id)      //如果要找的id和結點中的id相等,傳回資料
		return &root->data;

	if(id < root->data.id)        //如果要找的id小于結點中的id,再遞歸調用找左結點
		return find(root->l,id);
	return find(root->r,id);        //如果要找的id大于結點中的id,再遞歸調用找右結點
}
           

3.左偏 周遊輸出

static void draw_(struct node_st *root,int level)
{
    int i;
    if(root == NULL)    //root為NULL直接結束函數
        return ;    
    draw_(root->r,level+1);    //遞歸調用draw,指向右子樹,level+1    
    for(i = 0 ; i < level; i++)    //輸出level個空格
        printf("    ");
    print_s(&root->data);
    draw_(root->l,level+1);    遞歸調用draw,指向左子樹,level+1

}
void draw(struct node_st *root)
{
    draw_(root,0);

}
           
二叉樹(tree)一、二叉樹的周遊二、二叉樹程式

4.平衡二叉樹

static int get_num(struct node_st *root)    //傳回樹的結點個數
{
	if(root == NULL)
		return 0;
	return get_num(root->l) + 1 + get_num(root->r);//遞歸調用傳回結點個數
}
static struct node_st *find_min(struct node_st *root)
{
	if(root->l == NULL)   //如果root的左結點為NULL,将root傳回
		return root;        
	return find_min(root->l);    //遞歸調用查找左結點,當左結點為NULL,将這個結點傳回
}

static void turn_left(struct node_st **root)
{
	struct node_st *cur = *root;    //定義一個指針,指向*root指向的位置
	*root = cur->r;    //*root指向cur的右結點
	cur->r = NULL;       //cur的右結點指派為NULL
	find_min(*root)->l = cur;    //找到最小的結點,将cur插入到最小結點的左結點

//	draw(tree);
}

static struct node_st *find_max(struct node_st *root)
{
	if(root->r == NULL)    //如果root的左結點為NULL,将root傳回
		return root;
	return find_max(root->r);    //遞歸調用查找右結點,當右結點為NULL,将這個結點傳回
}  

static void turn_right(struct node_st **root)
{
	struct node_st *cur = *root;    //定義一個指針,指向*root指向的位置

	*root = cur->l;    //*root指向cur的左結點
	cur->l = NULL;    //cur的左結點指派為NULL
	find_max(*root)->r = cur;    //找到最大的結點,将cur插入到最大結點的右結點

//	draw(tree);
}

void balance(struct node_st **root)
{
	int sub;
	if(*root == NULL)
		return ;
	while(1)
	{
		sub = get_num((*root)->l) - get_num((*root)->r);    //得到根結點左子樹和右子樹的結點內插補點
		if(sub >= -1 && sub <= 1)    //兩邊的結點數內插補點如果是-1 0 1時結束循環
			break;
		if(sub < -1)                //如果內插補點小于-1,向左旋
			turn_left(root);
		else                        //如果內插補點大于1,向右旋
			turn_right(root);
	}

	balance(&(*root)->l);        //遞歸調用,平衡左子樹
	balance(&(*root)->r);        //遞歸調用,平衡右子樹

}
           
二叉樹(tree)一、二叉樹的周遊二、二叉樹程式

5.周遊

1)先序周遊

void travel(struct node_st *root) 
{
    if(root == NULL)
        return ;
    print_s(&root->data);
    travel(root->l);
    travel(root->r);
    
}
           

2)中序周遊

void travel(struct node_st *root) 
{
    if(root == NULL)
        return ;
    travel(root->l);
    print_s(&root->data);
    travel(root->r);
    
}
           

3)後序周遊

void travel(struct node_st *root) 
{
    if(root == NULL)
        return ;
    travel(root->l);
    travel(root->r);
    print_s(&root->data);
}
           

4)按層周遊

void travel(struct node_st *root)
{   
    QUEUE *qu;    
    struct node_st *cur;
    qu = queue_create(sizeof(struct node_st *));    //建立隊列
    queue_en(qu, &root);        //根結點入隊
    while(1)
    {   
        if(queue_de(qu, &cur) != 0)    //如果删除回顯不成功,則結束循環
            break;
        print_s(&cur->data);        //輸出回顯指針指向的資料
        if(cur->l != NULL)            //指針左結點不為NULL,則入隊
            queue_en(qu,&cur->l);    
        if(cur->r != NULL)            //指針右結點不為NULL,則入隊
            queue_en(qu,&cur->r);
    }   
    queue_destroy(qu);
}
           

6.删除結點

void delete(struct node_st **root, int id)
{
	struct node_st **node = root;
	struct node_st *cur;

	while( (*node) != NULL &&  (*node)->data.id != id )//查找要删除的結點
	{
		if( id < (*node)->data.id )    //如果想要删除的id小于結點中的id,讓指針指向結點的左結點
			node = &(*node)->l;
		else
			node = &(*node)->r;     //如果想要删除的id小于結點中的id,讓指針指向結點的左結點
	}
	
	if(*node == NULL)    //沒找到直接傳回
		return ;
	
	cur = *node;    

	if(cur->l == NULL)    //如果找到的結點的左子樹為NULL,則直接将*node指向cur的右結點
		*node = cur->r;
	else
	{
		*node = cur->l;    //不為NULL,則直接将*node指向cur的左結點
		find_max(cur->l)->r = cur->r;    //将找到的結點的右子樹插入到*node的右子樹的最後面
	}
	free(cur);

}