zoukankan      html  css  js  c++  java
  • 【算法学习笔记】09.数据结构基础 二叉树初步练习2

    此次重点在于 二叉树的结构体构造(指针的大量练习),数组方式构造(简易)

    建树的输入方式为,

    (11,LL) (7,LLL) (8,R) (5,) (4,L) (13,RL) (2,LLR) (1,RRR) (4,RR) () 

    ()表示结束LL表示从根节点开始向右移两次,并且同时延伸 (5,)表示根节点

    首先还是先来比较麻烦的结构体构造方法,但是看起来很高端。

    char s[100];//保存输入 
    int Failed=0,cnt=0; //表明是否输入有误 cnt是计数器 记录节点数目
    //定义结构体
    typedef struct Tnode //自定义一个结构体
    {
    	int hv;// have been valued
    	int v;//存储节点数值
    	struct Tnode *l,*r;//左右儿子 都是指向Tnode的指针 此时不能用Node*是因为Node还没有定义完全
    } Node;//命名在Node 
    //发现了 二叉树的定义过程中其实用到了递归的方法
    Node* root;//此为根节点 
    
    //此函数用来创建新node且为之申请动态内存 stdlib.h
    Node* newnode() 
    {
    	Node* u = (Node*)malloc(sizeof(Node)) ;//将申请来的内存格式化
    	if(u != NULL)//防止是非法内存
    	{
    		u->hv=0;//为u初始化
    		u->l=u->r=NULL;//还无左右儿子 连续赋值 必须赋值为空 否则后续无法判断是否为空
    	}
    	return u;//返回新建的节点
    }   
    //向已有的树上添加节点 v来赋值 s来确定节点位置
    void addnode(int v,char *s)
    {
    	//按照移动序列行走 *s =="LL)"
    	int len=strlen(s);//用来做循环控制
    	Node* u =root;//起点是root根节点 每一次寻找位置都要从根节点开始
    	for(int i=0;i<len;i++)
    	{
    		if(s[i]=='L')
    		{
    			if(u->l==NULL) u->l=newnode();//找到了空节点,说明要进行延伸
    			u=u->l;//向左走 //延伸了之后才能移动
    		}else if(s[i]=='R')
    		{
    			if(u->r==NULL) u->r=newnode();
    			u=u->r;//向左走 	
    		}
    	}
    <span style="white-space:pre">	</span>//此时已经找到了要赋值的节点了
    	if(u->hv) Failed=1;//如果输入有误则报错
    	else
    	{
    		u->v=v;
    		u->hv=1;
    	} 
    }
    //读入并建树
    int read()
    {
    	Failed=0;//每次新建树时要重置
    	remove_tree(root) ;//释放原有内存 
    	root = newnode();//为根节点进行初始化 ,建立一棵新树 主要是为了覆盖上一次的树 
    	for(;;)//不断地读入
    	{
    		if(scanf("%s",s)!=1)	
    			return 0;//表示输入结束 
    		//strcmp 的返回值比较奇葩 若str1=str2,则返回零 说明完全相同
    		if(!strcmp(s,"()")) break;//如果读入的是()就表示完成了一次输入 return 1
    		int v;//存储节点值
    		sscanf(&s[1],"%d",&v);//&s[1] 返回的是从s的第二个字符到结尾的数组 sscanf 从字符数组中读入v
    		addnode(v,strchr(s,',')+1);//strchr(s,',')返回的正好是','的指针,再+1 
    	}	 
    	return 1; 
    }
    void remove_tree(Node* u)
    {
    	if(u==NULL)
    		return;//走到某一个叶子时就return 
    	//利用递归循环删除 
    	remove_tree(u->l);
    	remove_tree(u->r);
    	free(u);
    	
    }
    
    

    此种方法的优点是比较易懂,后序过程时思考难度下降,并且是动态内存,所以不用管数据的大小

    还有一种避免指针的方式,就是用数组来进行建树。

    const int root=1; int left[10000],right[10000],cnt; int nodes[10000]={0};
    //left和right只用来记录节点之间的父子关系,且序号是按照输入顺序进行的
    //真正的数据值存储在nodes里
    bool failed = false; char s[100];
    //建立一棵新树,
    void newtree()
    {
    	left[root]=right[root]=0;
    	cnt=1;
    	memset(nodes,0,sizeof(nodes));
    } 
    int newnode()
    {
    <span style="white-space:pre">	</span>int u = ++cnt;//使cnt增加1  表明有了一个新的节点 
    <span style="white-space:pre">	</span>left[u]=right[u]=0;
    <span style="white-space:pre">	</span>return u;//返回u 
    }
    
    
    void addnode(int v,char *s)//值v s= LL) 
    {
    <span style="white-space:pre">	</span>int len= strlen(s);
    <span style="white-space:pre">	</span>int t=root;
    <span style="white-space:pre">	</span>for(int i=0;i<len;i++) 
    <span style="white-space:pre">	</span>{
    <span style="white-space:pre">		</span>//先找到节点位置,如果遇到空就建立新节点 
    <span style="white-space:pre">		</span>if(s[i]=='L')
    <span style="white-space:pre">		</span>{
    <span style="white-space:pre">			</span>if(left[t]==0)
    <span style="white-space:pre">				</span>left[t]=newnode();//如果当前的左边是空的就建立一个节点
    <span style="white-space:pre">			</span>t=left[t];//向左走  
    <span style="white-space:pre">		</span>}else
    <span style="white-space:pre">		</span>{
    <span style="white-space:pre">			</span>if(s[i]=='R')
    <span style="white-space:pre">			</span>{
    <span style="white-space:pre">				</span>if(right[t]==0)
    <span style="white-space:pre">					</span>right[t]=newnode();//如果当前的左边是空的就建立一个节点
    <span style="white-space:pre">				</span>t=right[t];//向左走  
    <span style="white-space:pre">			</span>}
    <span style="white-space:pre">		</span>} 
    <span style="white-space:pre">	</span>}
    <span style="white-space:pre">	</span>if(nodes[t])
    <span style="white-space:pre">		</span>failed = true;
    <span style="white-space:pre">	</span>else
    <span style="white-space:pre">		</span>nodes[t]=v;
    <span style="white-space:pre">		</span> 
    }   
    int read()
    {
    <span style="white-space:pre">	</span>newtree();
    <span style="white-space:pre">	</span>while(scanf("%s",s)==1)
    <span style="white-space:pre">	</span>{
    <span style="white-space:pre">		</span>if(!strcmp(s,"()")) 
    <span style="white-space:pre">			</span>return 1;//结束 
    <span style="white-space:pre">		</span>int d=0;
    <span style="white-space:pre">		</span>sscanf(&s[1],"%d",&d);
    <span style="white-space:pre">		</span>addnode(d,strchr(s,',')+1);
    <span style="white-space:pre">	</span>}
    <span style="white-space:pre">	</span>return 0;
    }  
    

    
    代码其实并没有减少多少,说简单了但是其实也有点复杂 比如left right nodes 三个数组之间的关系有时候会闹不清楚

  • 相关阅读:
    VIM的强大功能
    BigDecimal.ROUND_HALF_XXX的各种用法
    拒绝服务攻击
    浅谈(接口)测试注意事项四
    jmeter 与 java http
    Xms Xmx PermSize MaxPermSize 区别
    Jquery过滤器
    JQ工具函数运用
    C#扩展方法
    LINQ TO XML基础
  • 原文地址:https://www.cnblogs.com/yuchenlin/p/4379265.html
Copyright © 2011-2022 走看看