算法-树的相关算法


树是一种递归的数据结构。树的种类从子孩子的数目上可以简单分为二叉树和多叉树。其中二叉树常见的考虑有红黑树和AVL树。另外,多叉树常见的有B树系列、Trie树系列。


有关树的算法可以从最基础的遍历(前中后层)、遍历延伸(公共祖先、对称树)、集合思想(并查集找直系亲属)。

1.遍历

遍历就是按照一定的顺序访问树的节点,由于树是非线性结构,遍历树其实就是将非线性结构转换为线性序列展示。

前、中、后遍历常有的是递归遍历和非递归遍历。

1.1递归访问的模式如下:

<span style="font-size:18px;">void Order(TreeNode *root)
{  
  if(root != NULL) 
{         //preVisit(T);         //前序访问根节点  
        Order(T->lchild);   //访问左子结点  
        //inVisit(T);           //中序访问根节点  
        Order(T->rchild);  //访问右子结点   
        //postVisit(T);        //后序访问根节点  

    }  
} </span>


 

 

1.2非递归遍历

非递归算法主要是利用循环+栈数据结构实现的。模式如下

1.2.1先序或中序遍历(非递归)

   思路:访问T->data后,将T入栈,(先序遍历左子树);遍历完左子树返回时,栈顶元素应为T,(中序遍历左子树),出栈,再遍历T的右子树。

<span style="font-size:18px;">void Order2(TreeNode* root)
{
	stack<TreeNode*> stack;
	TreeNode*p = root;//p是遍历指针
	while(p || !stack.empty())//栈不空或者p不空时循环
<span style="white-space:pre">	</span>{
		if(p != NULL)
<span style="white-space:pre">		</span>{
			stack.push(p);//存入栈中	
			//preVisit(p);//前序遍历访问根节点
			p = p->lchild;//遍历左子树
		}
		else
<span style="white-space:pre">		</span>{	
			p = stack.top();//退栈
			//inVisit(p);//中序遍历访问根节点
			stack.pop();
			p = p->rchild;//遍历右子树
		}
<span style="white-space:pre">	</span>}
}</span>


 

1.2.2后序遍历.

有一篇经典的总结非递归遍历二叉树的方法  http://www.jianshu.com/p/49c8cfd07410

总结出来的模式为

<span style="font-size:18px;">void order(TreeNode *root, vector<int> &path)
{
    stack< pair<TreeNode *, bool> > s;
    s.push(make_pair(root, false));
    bool visited;
    while(!s.empty())
    {
        root = s.top().first;
        visited = s.top().second;
        s.pop();
        if(root == NULL)
            continue;
        if(visited)
        {
            path.push_back(root->val);//访问根节点
        }
        else
        {
            //s.push(make_pair(root, true));//后序遍历,访问根节点<span style="font-family: Arial, Helvetica, sans-serif;">权限开通</span>
            s.push(make_pair(root->right, false));
            //s.push(make_pair(root, true));//中序遍历,访问根节点权限开通
            s.push(make_pair(root->left, false));
            //s.push(make_pair(root, true));//前序遍历,访问根节点权限开通
        }
    }
}</span>


1.2.3层序遍历(队列)

层序遍历相对简单,采用队列思维,每层压队列,直到队列为空即可结束。

</pre><p><span style="font-size:18px;"></span></p><h2><span style="font-size:18px;">1.3公共祖先问题</span></h2><div><span style="font-size:18px;">求解公共祖先问题主要有:<span style="font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25.2px;">在线法和离线法.</span></span><p style="margin: 10px auto; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25.2px;"><span style="font-size:18px;">在线法:指每提出一次请求,便给出一次应答</span></p><p style="margin: 10px auto; font-family: verdana, Arial, Helvetica, sans-serif; line-height: 25.2px;"><span style="font-size:18px;">离线法:收集所有的请求,然后统一进行处理</span></p></div><p><span style="font-size:18px;">1.3.1采用递归方法求公共祖先</span><pre name="code" class="cpp"><span style="font-size:18px;">/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution 
{
public:
    TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) 
    {
        if(root == NULL || root == p || root == q) return root;

        TreeNode *ltree = lowestCommonAncestor(root->left,p,q);
        TreeNode *rtree = lowestCommonAncestor(root->right,p,q);

        if(ltree && rtree) return root;

        return ltree?ltree:rtree;
    }
  
};</span>

1.3.2Tarjan算法(离线法dfs+并查集)

算法的基本思想为:任选一结点开始进行深度优先搜索dfs(若深度优先搜索结束后仍有未访问的结点,则再从中任选一点再次进行)。搜索过程中已访问的结点不再访问。搜索树的若干子树构成了图的强连通分量。

推荐一篇文章:http://blog.csdn.net/v_july_v/article/details/18312089


1.3.3RMQ算法(在线法dfs+RMQ)

 RMQ,全称为Range Minimum Query,顾名思义,则是区间最值查询,它被用来在数组中查找两个指定索引中最小值的位置。

推荐一篇文章:http://www.cnblogs.com/qianye/archive/2012/12/03/2800384.html

1.4 对称树

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值