更新一下树的学习笔记
首先树不同于二叉树,它可以增加任意多的子节点,更符合我们日常的使用习惯。
本文建立的树使用以下结构:
存放数据的结构体:

typedef struct _data{
	int id;
	char name[20];
}data;

存放节点的结构体:

typedef struct _node{
	data *d;
	struct _node *parent,*first_child,*last_child,*next_sibling,*prev_sibling;
}node;

树的控制块:

typedef struct _tree{
	node *root;
}tree;

然后导入数据用的一个数组:

typedef struct _bom{
	int id;
	char name[20];
	int pid;
}bom;

树的子节点很多关系也复杂,但是如果能像二叉树那样获取一个节点的下一个节点事实上操作就会明了很多。所以要先编写获取前一个节点和后一个节点以及获取子树最后一个节点的函数。这些是后续操作的基础。

node *tree_get_next(node *n){
	if(n==NULL){
		return NULL;
	}
	
	if(n->first_child!=NULL){
		return n->first_child;
	}else if(n->next_sibling!=NULL){
		return n->next_sibling;
	}else{
		node *t = n->parent;
		while(t!=NULL&&t->next_sibling==NULL){
			t = t->parent;
		}
		
		if(t != NULL){
			return t->next_sibling;
		}else{
			return NULL;
		}
	}
}

node *tree_get_prev(node *n){
	if(n->prev_sibling!=NULL){
		if(n->prev_sibling->last_child!=NULL){
			node *p = n->prev_sibling->last_child;
			while(p->last_child!=NULL){
				p=p->last_child;
			}
			return p;
		}else{
			return n->prev_sibling;
		}
	}else{
		if(n->parent!=NULL){
			return n->parent;
		}else{
			return NULL;
		}
	}
}

node *tree_get_last_child(node *n){
	while(n!=NULL&&n->last_child!=NULL){
		n=n->last_child;
	}
	return n;
}

有了这些函数作支持,很容易写出查找函数。

node *tree_find_node(tree *t,int id){
	node *n = t->root;
	while(n!=NULL){
		if(n->d->id==id){
			return n;
		}
		n = tree_get_next(n);
	}
	return NULL;
}

写出查找函数之后也就可以继续完成添加节点的操作了:

int tree_add_node(tree *t,int pid,data *d){
	//1.search target of this pid
	node *n = tree_find_node(t,pid);
	if(n==NULL&&t->root!=NULL){
		return 0;
	}
	
	//2.create the node of data
	node *p = (node *)malloc(sizeof(node));
	if(p==NULL){
		printf("Overflow");
		return 0;
	}
	p->d = d;
	p->first_child=NULL;
	p->last_child=NULL;
	p->next_sibling=NULL;
	p->parent=NULL;
	p->prev_sibling=NULL;
	
	//3.create or modify the parent node's child pointer
	p->parent=n;
	if(t->root==NULL){
		t->root=p;
	}else if(n->first_child==NULL){
		n->first_child=p;
		n->last_child=p;
	}else{
		n->last_child->next_sibling=p;
		p->prev_sibling=n->last_child;
		n->last_child=p;
	}
	 
	return -1;
}

遍历操作:

void tree_iterate(tree *t){
	node *n = t->root;
	while(n!=NULL){
		printf("\n%d",n->d->id);
		n=tree_get_next(n);
	}
}

从树上面取出子树也是一个常用的操作,对后面的子树进行取出操作:

node *tree_extract(tree *t,int id){
	//1.查找节点->判断节点是否为空或根节点 
	node *n = tree_find_node(t,id);
	if(n==NULL){
		printf("节点没有找到");
		return NULL;
	}
	if(n->parent==NULL){
		printf("不能删除根节点");
		return NULL;
	}
	
	//2.调整指针,分离节点(子树)
	if(n->next_sibling==NULL&&n->prev_sibling==NULL){
		n->parent->first_child=NULL;
		n->parent->last_child=NULL;
	}else if(n->prev_sibling==NULL){
		n->parent->first_child=n->next_sibling;
		n->next_sibling->prev_sibling=NULL;
	}else if(n->next_sibling==NULL){
		n->parent->last_child=n->prev_sibling;
		n->prev_sibling->next_sibling=NULL;
	}else{
		n->prev_sibling->next_sibling=n->next_sibling;
		n->next_sibling->prev_sibling=n->prev_sibling;
	}
	n->parent=NULL;
	n->next_sibling=NULL;
	n->prev_sibling=NULL;
	
	return n;
}

剪枝操作:

//剪枝删除 
int tree_cut(tree *t,int id){
	//extract函数分离要剪枝的节点(子树)
	node *n = tree_extract(t,id);
	if(n==NULL){
		return 0;
	}
	
	//2.析构子树,释放空间。此处注意倒序析构
	n=tree_get_last_child(n);
	while(n!=NULL){
		node *t=tree_get_prev(n);
		free(n->d);
		free(n);
		n=t;
	}
	return -1; 
}

清空树操作:

int tree_empty(tree *t){
	node *n=tree_get_last_child(t->root);
	while(n!=NULL){
		node *t = tree_get_prev(n);
		free(n->d);
		free(n);
		n=t;
	}
	return -1;
}

有时候需要判断两个节点间是否存在父子关系(这个实际上可以用于上下级关系的查询?):

int tree_has_as_parent(tree *t,int id,int pid){
	if(id==pid){
		return 0;
	}
	
	//判断节点是否存在
	node *n=tree_find_node(t,id);
	if(n==NULL){
		return 0;
	}
	node *pn=tree_find_node(t,pid);
	if(pn==NULL){
		return 0;
	}
	
	n=n->parent;
	while(n!=NULL){
		if(n->d->id==id){
			return -1;
		}
		n=n->parent;
	}
	
	return 0;
}

最后完成的是父节点重构,稍微有点复杂,但是和前面的操作很类似,分为5步进行:

int tree_reparent(tree *t,int id,int pid){
	//1.判定是否重构到自己 
	if(id==pid){
		return(0);
	} 
	
	//2.判定id,pid是否存在 
	node *n=tree_find_node(t,id);
	if(n==NULL){
		return(0);
	}
	
	node *pn=tree_find_node(t,pid);
	if(pn==NULL){
		return(0);
	}
	
	//3.判断是否重构到子节点上或者id为根节点 
	/* 
	if(tree_has_as_parent(t,id,pid)){
		return 0;
	}
	*/
	if(n->parent==NULL||n->parent->d->id==pid){
		return 0;
	}
	
	node *p=pn->parent;
	while(p!=NULL){
		if(p->d->id==pid){
			return 0;
		}
		p=p->parent;
	}
	
	//4.提取id节点(子树)
	if(n->prev_sibling==NULL&&n->next_sibling==NULL){
		n->parent->first_child=NULL;
		n->parent->last_child=NULL;
	}else if(n->prev_sibling==NULL){
		n->parent->first_child=n->next_sibling;
		n->next_sibling->prev_sibling=NULL;
	}else if(n->next_sibling==NULL){
		n->parent->last_child=n->prev_sibling;
		n->prev_sibling->next_sibling=NULL;
	}else{
		n->prev_sibling->next_sibling=n->next_sibling;
		n->next_sibling->prev_sibling=n->prev_sibling;
	}
	n->parent=pn;
	n->next_sibling=NULL;
	n->prev_sibling=NULL;
	
	//5.将id节点加入pid节点
	if(pn->first_child==NULL){
		pn->first_child=n;
		pn->last_child=n;
	}else{
		//加到尾部
		pn->last_child->next_sibling=n;
		n->prev_sibling=pn->last_child;
		pn->last_child=n; 
	}
	
	return -1;
}

最后编写一个main函数测试一下:

int main() {
		bom bs[]={
		{1,"",-1},
		
		{2,"",1},
		{3,"",1},
		{4,"",1},
		
		{5,"",2},
		{6,"",2},
		{7,"",2},
		
		{8,"",3},
		{9,"",3},
		{10,"",3},
		
		{11,"",5},
		{12,"",5},
		{13,"",5}, 

		{14,"",9},
		{15,"",9},
		{16,"",9}
	}; 
	//create a new tree
	data *d;
	tree *t=(tree *)malloc(sizeof(tree));
	if(t==NULL){
		printf("overflow");
		return;
	}
	t->root=NULL;
	
	//add nodes, golang JSON->dimension
	int i;
	for(i=0;i<16;i++){
		d=(data *)malloc(sizeof(data));
		d->id=bs[i].id;
		tree_add_node(t,bs[i].pid,d);
	}
	
	//dfs(depth first search): iterate through the tree,bfs(breadth first search)
	tree_iterate(t);
	
	node *n=tree_get_last_child(t->root);
	if(n!=NULL){
		printf("\nlast child:%d",n->d->id);
	}else{
		printf("\nnot found!");
	}
	
	printf("\nreverse iterate:");
	if(n!=NULL){
		printf("\n%d",n->d->id);
		n=tree_get_prev(n);
		
		while(n!=NULL){
			printf("\n%d",n->d->id);
			n=tree_get_prev(n);
		}
	}
	
	n=tree_find_node(t,3);
	if(n==NULL){
		exit(0);
	}
	
	
	
	n=tree_get_last_child(n);
	if(n!=NULL){
		printf("\nlast child:%d",n->d->id);
	}else{
		printf("\nnot found!");
	}
	
	printf("\nreverse iterate:");
	if(n!=NULL){
		printf("\n%d",n->d->id);
	
		n=tree_get_prev(n);
		while(n!=NULL){
			printf("\n%d",n->d->id);
			if(n->d->id==3){
				break;
			}
			n=tree_get_prev(n);
		}
	}
	
	printf("\n=======================");
	//tree_cut(t,3);
	tree_reparent(t,5,4);
	tree_iterate(t);
	
	//suspend
	getch();
}
//END

完成。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值