算法基础-- >树

本篇博文将总结关于树的一些算法,树部分的内容挺多,但是不难,主要考察的是coding能力,本人就是感觉自己coding能力太差,所以关于代码实现部分都要自己实现一遍,不会的在网上查资料跟着敲一遍。

树和二叉树的关系

一般地说,树的结点间是无序 的,即:一个结点有m个孩子,则 L 1 , L 2 , L 3 , . . . , L m {L}_{1},{L}_{2},{L}_{3},...,{L}_{m} L1,L2,L3,...,Lm 可以互换位置,仍然认为是同一颗树

二叉树的两个孩子,一般称为左孩子、右孩子,不能互换位置。之所以这样定义,是因为有些算法,需要严格区分左右孩子,如前序-中序-后序遍历、堆排序等问题。

从这个意义上说,树和二叉树是两个概念,不能说二叉树是树的子集

树转换成二叉树

  • 任意一棵 树转换成二叉树,右孩子为空的数目为原树非叶结点+1。
    对于一颗树(非二叉树),因为任何一个非叶结点必然有孩子,所以,它必然有最右孩子。从而,这个最右孩子转换到二叉树结点后,右指针必然为空。
    同时,根结点必然没有兄弟,所以,根结点转换成二叉树结点后,必然右孩子为空。

  • 任意棵 树转换成二叉树,右孩子为空的数目为原树非叶结点+1
    如果是若干个树转二叉树,这若干个树最右边的那个树,是没有右孩子的。

这里写图片描述

树基本操作

  • 插入
  • 删除
  • 查找

实现的头文件代码:treeNode.h

#include<stdio.h>
#include <stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;

typedef struct tagsTreeNode{
	int value;
	tagsTreeNode* pLeft;
	tagsTreeNode* pRight;
	tagsTreeNode(int v) :value(v), pLeft(NULL), pRight(NULL){}
}STreeNode;

typedef void(*VISIT)(int value);

class CBinaryTree
{
private:
	STreeNode* m_pRoot;
private:
	STreeNode* Find(int value) ; //二叉查找树查找
	void destroy(STreeNode* pRoot) ;
	void Delete(int value);
	bool insert(STreeNode* pRoot, int value) ;//递归
	bool insert2(int vlaue) ;//非递归
	void PreOrder(STreeNode* pRoot, VISIT Visit) ;
	void PreOrder2(VISIT Visit) ;
	void InOrder(STreeNode* pRoot, VISIT Visit) ;
	void Inorder2(VISIT Visit) ;
	void Inorder3(VISIT Visit) ;
	void PostOrder(STreeNode* pRoot, VISIT Visit) ;
	void PostOrder2(VISIT Visit) ;
	void DeleteChildless(STreeNode* pParent, STreeNode* pNode);
	void DeleteSingleSon(STreeNode* pParent, STreeNode* pNode);
	void DeleteDoubleSon(STreeNode* pNode);
};

从上面的代码也可以看出,树在代码的实现上其实是利用了链表的形式。

二叉查找树

二叉查找树(二叉搜索树)是满足以下条件的二叉树:

  • 左子树上的所有结点值均小于根结点值,
  • 右子树上的所有结点值均不小于根结点值,
  • 左右子树也满足上述两个条件。

这里写图片描述

查找

查找一般是针对二叉查找树而言。

查找步骤

给定一颗二叉查找树,查找某结点 p p p 的过程如下:

  1. 将当前结点 c u r cur cur 赋值为根结点 r o o t root root
  2. p p p 的值小于当前结点 c u r cur cur 的值,查找 c u r cur cur 的左子树;
  3. p p p 的值不小于当前结点 c u r cur cur 的值,查找 c u r cur cur 的右子树;
  4. 递归 上述过程,直到 c u r cur cur 的值等于 p p p 的值或者 c u r cur cur 为空;
    当然,若结点是结构体,注意定义“小于”“不小于”“等于”的具体函数。
#include<treeNode.h>

STreeNode* CBinaryTree::Find(int value) 
{
	if (!m_pRoot)
		return NULL;
	STreeNode* pNode = m_pRoot;
	while (pNode)
	{
		if (value < pNode->value)
			pNode = pNode->pLeft;
		else if (value>pNode->value)
			pNode = pNode->pRight;
		else
			return pNode;
	}
	return NULL;
}

插入

插入操作一般也是针对二叉查找树而言。

插入步骤:
  1. 若当前的二叉查找树为空,则插入的元素为根结点,
  2. 若插入的元素值小于根结点值,则将元素插入到左子树中,
  3. 若插入的元素值不小于根结点值,则将元素插入到右子树中,
  4. 递归 上述过程,直到找到插入点为叶子结点。

递归插入代码:

bool CBinaryTree::insert(STreeNode* pRoot, int value) 
{
	if (!pRoot)
	{
		pRoot = new STreeNode(value);//如果根结点为空,则插入元素即为根结点
		return true;
	}
	if (value < pRoot->value)
		return insert(pRoot->pLeft, value);
	else if (value>pRoot->value)
		return insert(pRoot->pRight, value);
	return false;//如果插入元素的值和树中某结点的值相等,则说明该结点已经存在,返回false,不用进行插入
}

非递归插入代码:

bool CBinaryTree::insert2(int value)
{
	if (!m_pRoot)
	{
		m_pRoot = new STreeNode(value);
	}
	STreeNode *pNode = m_pRoot;
	STreeNode *pCur = m_pRoot;
	while (pNode)
	{
		pCur = pNode;//只有pNode为空时才会停止循环,所以把pNode为空之前的那个结点给pCur保存
		if (value < pNode->value)
			pNode = pNode->pLeft;
		else if (value>pNode->value)
			pNode = pNode->pRight;
		else
			return false;
	}
	if (value < pCur->value)
		pCur->pLeft = new STreeNode(value);
	else if (value>pCur->value)
		pCur->pRight = new STreeNode(value);
	return true;
}

删除

记待删除的结点为 p p p ,分三种情况进行处理:

  • p p p 为叶子结点
  • p p p 为单支结点
  • p p p 的左子树和右子树均不空
待删除点为叶子结点

p p p 为叶子结点,直接删除该结点,再修改 p p p 的父结点的指针。

这里写图片描述

代码实现:

void CBinaryTree::DeleteChildless(STreeNode* pParent, STreeNode* pNode)//pParen为pNode结点的父结点
{
	if (m_pRoot == pNode)
		m_pRoot = NULL;
	else if (pParent->pLeft == pNode)
		pParent->pLeft = NULL;
	else
		pParent->pRight = NULL;
	delete pNode;
}
待删除点只有一个孩子

p p p 为单支结点(即只有左子树或右子树),则将 p p p 的子树与 p p p 的父亲结点相连,删除 p p p 即可

这里写图片描述

代码实现:

void CBinaryTree::DeleteSingleSon(STreeNode* pParent, STreeNode* pNode)
{
	STreeNode* pGrandSon = pNode->pLeft ? pNode->pLeft : pNode->pRight;
	if (m_pRoot == pNode)
		m_pRoot = pGrandSon;
	else if (pParent->pLeft = pNode)
		pParent->pLeft = pGrandSon;
	else
		pParent->pRight = pGrandSon;
	delete pNode;
}
待删除点有两个孩子

这个操作相比上面有点麻烦。

p p p 的左子树和右子树均不空,则找到 p p p直接后继(中序遍历的直接后继) d d d (*** p p p 的右孩子的最左子孙*** ),因为 d d d 一定没有左子树,所以使用删除单支结点的方法:删除 d d d,并让 d d d 的父亲结点 d p dp dp 成为 d d d 的右子树的父亲结点;同时,用 d d d 的值代替 p p p 的值;

对偶的:可以找到 p p p直接前驱 (中序遍历的直接前驱) x x x ( p p p 的左孩子的最右子孙** ), x x x 一定没有右子树,所以可以删除 x x x,并让 x x x 的父亲结点成为 x x x 的左子树的父亲结点。

  1. p p p 的直接后继的值拷贝到 p p p
  2. 删除 p p p 的直接后继。

这里写图片描述

代码实现(这里是上面的对偶过程):

void CBinaryTree::DeleteDoubleSon(STreeNode* pNode)//要删除的结点pNode
{
	STreeNode* pCur = pNode;//暂存待删结点
	STreeNode* pParent = pNode;
	//pNode的左孩子的最右子孙 
	pNode = pNode->pLeft;
	while (pNode->pRight)
	{
		pParent = pNode;
		pNode = pNode->pRight;
	}
	pCur->value = pNode->value;//将要删除结点的左孩子的最右子孙的值赋值给要删除结点的值 
	//然后将要删除结点的左孩子的最右子孙结点删除。
	if (!pNode->pLeft)
		DeleteChildless(pParent, pNode);
	else
		DeleteSingleSon(pParent, pNode);
}

整合一下上面的三种情况下的删除方法:

bool CBinaryTree::Delete(int value)//要删除结点的值为value
{
	if (!m_pRoot)
		return false;
	STreeNode* pNode = m_pRoot;
	STreeNode* pParent = NULL;

	while (pNode)
	{
		if (value < pNode->value)
		{
			pParent = pNode;
			pNode = pNode->pLeft;
		}
		else if (value > pNode->value)
		{
			pParent = pNode;
			pNode = pNode->pRight;
		}
		else//找到要删除的结点pNode
			break;
	}
	if (!pNode)
		return false;
	if (!pNode->pLeft&&!pNode->pRight)
		DeleteChildless(pParent, pNode);//要删除的结点是叶子结点
	else if (!pNode->pLeft || pNode->pRight)
		DeleteSingleSon(pParent, pNode);//要删除的结点有一个子结点
	else
		DeleteDoubleSon(pNode);//要删除的结点有两个子结点。
	return true;
}

二叉树的遍历

前序遍历:

  • 访问根结点
  • 前序遍历左子树
  • 前序遍历右子树

中序遍历:

  • 中序遍历左子树
  • 访问根结点
  • 中序遍历右子树

后序遍历:

  • 后序遍历左子树
  • 后序遍历右子树
  • 访问根结点

前序遍历

这里写图片描述

前序遍历: 15 , 5 , 3 , 12 , 10 , 6 , 7 , 13 , 16 , 20 , 18 , 23 15,5,3,12,10,6,7,13,16,20,18,23 15,5,3,12,10,6,7,13,16,20,18,23
JAVA Node类定义

public class Node{
    public int value;
    public Node left;
    public Node right;

    public Node(int data){
        this.value = data;
    }
}

JAVA版 Mirror遍历(二叉树的神级遍历)其先中后序遍历时间复杂度O(N),空间复杂度O(1)

public class Morrirs {
    public void func(Node head) {
        if (head == null) {
            return;
        }
        Node cur = head;
        Node mostRight = null;
        while (cur != null) {
            if (cur.left != null) {
                mostRight = cur.left;
                while (mostRight.right != null && mostRight.right != cur) {
                    mostRight = mostRight.right;
                }
                if (mostRight.right != cur) {
                    System.out.println(cur.value);
                    mostRight.right = cur;
                    cur = cur.left;
                    continue;
                } else {
                    mostRight.right = null;
                }
            }
            System.out.println(cur.value);
            cur = cur.right;
        }
    }

    public static void main(String[] args) {
        Morrirs obj = new Morrirs();
        Node node4 = new Node(4);
        Node node2 = new Node(2);
        Node node1 = new Node(1);
        Node node3 = new Node(3);
        Node node6 = new Node(6);
        Node node5 = new Node(5);
        Node node7 = new Node(7);
        node4.left = node2;
        node4.right = node6;
        node2.left = node1;
        node2.right = node3;
        node6.left = node5;
        node6.right = node7;
        node1.left = null;
        node1.right = null;
        node5.left = null;
        node5.right = null;
        node7.left = null;
        node7.right = null;
        obj.func(node4);
    }
}

JAVA mirror先序遍历

public void func(Node head) {
        if (head == null) {
            return;
        }
        Node cur = head;
        Node mostRight = null;
        while (cur != null) {
            if (cur.left != null) {
                mostRight = cur.left;
                while (mostRight.right != null && mostRight.right != cur) {
                    mostRight = mostRight.right;
                }
                if (mostRight.right != cur) {
                    System.out.println(cur.value);
                    mostRight.right = cur;
                    cur = cur.left;
                    continue;
                } else {
                    mostRight.right = null;
                }
            }
            else{
                System.out.println(cur.value);
            }
            cur = cur.right;
        }
    }

JAVA 普通版 非递归先序遍历(时间复杂度O(N),空间复杂度O(N))

public void func(Node head) {
        if (head == null)
            return;
        Stack<Node> stack = new Stack<>();
        stack.push(head);
        while (!stack.isEmpty()) {
            Node cur = stack.pop();
            System.out.println(cur.value);
            if (cur.right != null)
                stack.push(cur.right);
            if (cur.left != null)
                stack.push(cur.left);
        }
    }

c++ 递归代码:

void CBinaryTree::PreOrder(STreeNode* pRoot, VISIT Visit)
{
	if (pRoot)
	{
		Visit(pRoot->value);
		PreOrder(pRoot->pLeft, Visit);
		PreOrder(pRoot->pRight, Visit);
	}
}

c++ 非递归代码:

void CBinaryTree::PostOrder2(VISIT Visit)
{
	if (!m_pRoot)
		return;
	stack<STreeNode*> s;
	s.push(m_pRoot);//把根结点压进堆栈
	STreeNode* pCur;
	while (!s.empty())
	{
		pCur = s.top();//获取stack头元素
		s.pop();//弹栈
		Visit(pCur->value);//按照前序遍历顺序,先访问根节点
		// 按照右左顺序压栈,然后弹栈顺序就是左右,那么访问顺序就是左右
		if (pCur->pRight)
			s.push(pCur->pRight);
		if (pCur->pLeft)
			s.push(pCur->pLeft);
	}
}

中序遍历

这里写图片描述

中序遍历: 3 , 5 , 6 , 7 , 10 , 12 , 13 , 15 , 16 , 18 , 20 , 23 3,5,6,7,10,12,13,15,16,18,20,23 3,5,6,7,10,12,13,15,16,18,20,23
二叉查找树的中序遍历,即为数据的升序过程。

java版 mirror先序遍历

public void func(Node head) {
        if (head == null) {
            return;
        }
        Node cur = head;
        Node mostRight = null;
        while (cur != null) {
            if (cur.left != null) {
                mostRight = cur.left;
                while (mostRight.right != null && mostRight.right != cur) {
                    mostRight = mostRight.right;
                }
                if (mostRight.right != cur) {
                    //System.out.println(cur.value);
                    mostRight.right = cur;
                    cur = cur.left;
                    continue;
                } else {
                    mostRight.right = null;
                }
            }
            //else{
                System.out.println(cur.value);
            //}
            cur = cur.right;
        }
    }

JAVA 普通版非递归中序遍历,时间复杂度O(N), 空间复杂度O(N)

public void func(Node head) {
        if (head == null)
            return;
        Stack<Node> stack = new Stack<>();
        Node cur = head;    
        while (cur != null || !stack.isEmpty()) {
            if (cur != null) {
                while (cur != null) {
                    stack.push(cur);
                    cur = cur.left;
                }
            }else{
                cur = stack.pop();
                System.out.println(cur.value);
                cur = cur.right;
            }
        }
    }

递归代码:

void CBinaryTree::InOrder(STreeNode* pRoot, VISIT Visit)
{
	if (pRoot)
	{
		InOrder(pRoot->pLeft, Visit);
		Visit(pRoot->value);
		InOrder(pRoot->pRight, Visit);
	}
}

非递归代码:

void CBinaryTree::InOrder2(VISIT Visit)
{
	stack<STreeNode*> s;
	STreeNode* pCur = m_pRoot;
	while (pCur||!s.empty())
	{
		while (pCur)//寻找最左孩子
		{
			s.push(pCur);
			pCur = pCur->pLeft;
		}
		if (!s.empty())
		{
			pCur = s.top();//访问左孩子为空的结点
			s.pop();//栈顶元素弹栈
			Visit(pCur->value);
			pCur = pCur->pRight;//转向右孩子
		}
	}
}

还可以这样的进行非递归的中序遍历:

void CBinaryTree::InOrder3(VISIT Visit)
{
	if (!m_pRoot)
		return;
	stack<pair<STreeNode*, int> > s;//结点和结点对应的压栈次数
	s.push(make_pair(m_pRoot, 0));
	int times;
	STreeNode* pCur;
	while (!s.empty())
	{
		pCur = s.top().first;
		times = s.top().second;
		s.pop();
		if (times == 0)//第一次压栈
		{
			//中序访问顺序:左根右;则压栈顺序:右根左
			if (pCur->pRight)
				s.push(make_pair(pCur->pRight,0));
			s.push(make_pair(pCur, 1));//第二次压栈
			if (pCur->pLeft)
				s.push(make_pair(pCur->pLeft, 0));
		}
		else//只有压栈次数大于0才能访问
		{
			Visit(pCur->value);
		}
	}
}

后序遍历

这里写图片描述

后序遍历: 3 , 7 , 6 , 10 , 13 , 12 , 5 , 18 , 23 , 20 , 16 , 15 3,7,6,10,13,12,5,18,23,20,16,15 3,7,6,10,13,12,5,18,23,20,16,15
Morri后序遍历

public void func(Node head) {
        if (head == null) {
            return;
        }
        Node cur = head;
        Node mostRight = null;
        while (cur != null) {
            if (cur.left != null) {
                mostRight = cur.left;
                while (mostRight.right != null && mostRight.right != cur) {
                    mostRight = mostRight.right;
                }
                if (mostRight.right == null) {
                    mostRight.right = cur;
                    cur = cur.left;
                    continue;
                } else {
                    mostRight.right = null;
                    printReverseVertex(cur.left);
                }
            }
            cur = cur.right;
        }
        printReverseVertex(head);
    }

    public void printReverseVertex(Node node) {
        Node tail = reverse(node);
        Node cur = tail;
        while(cur != null){
            System.out.println(cur.value);
            cur = cur.right;
        }
        reverse(tail);
    }

    public Node reverse(Node node) {
        Node pre = null;
        Node next = null;
        while (node != null) {
            next = node.right;
            node.right = pre;
            pre = node;
            node = next;
        }
        return pre;
    }

JAVA 普通版后序遍历 时间复杂度O(N),空间复杂度O(N)

 public void func(Node head){
        Stack<Node> stack = new Stack<>();
        Stack<Node> stack2 = new Stack<>();
        stack.push(head);
        while(!stack.isEmpty()){
            Node cur = stack.pop();
            stack2.push(cur);
            if(cur.left != null)
                stack.push(cur.left);
            if(cur.right != null)
                stack.push(cur.right);
        }
        while(!stack2.isEmpty()){
            Node cur = stack2.pop();
            System.out.println(cur.value);
        }
    }

递归代码:

void CBinaryTree::PostOrder(STreeNode* pRoot, VISIT Visit)
{
	if (pRoot)
	{
		InOrder(pRoot->pLeft, Visit);
		InOrder(pRoot->pRight, Visit);
		Visit(pRoot->value);
	}
}

非递归代码:

void CBinaryTree::PostOrder2(VISIT Visit)
{
	if (!m_pRoot)
		return;

	stack<pair<STreeNode*, int>> s;
	s.push(make_pair(m_pRoot, 0));
	STreeNode* pCur;
	int time;
	while (!s.empty())
	{
		pCur = s.top().first;
		time = s.top().second;
		s.pop();
		if (time == 0)//第一次压栈
		{
			//后序访问顺序:左右根,则压栈顺序:根右左
			s.push(make_pair(pCur, 1));//第二次压栈
			if (pCur->pLeft)
				s.push(make_pair(pCur->pLeft, 0));
			if (pCur->pRight)
				s.push(make_pair(pCur->pRight, 0));
		}
		else
		{
			Visit(pCur->value);
		}
	}
}

根据前序中序,计算后序

如:已知某二叉树的遍历结果如下,求它的后序遍历序列

前序遍历: G D A F E M H Z GDAFEMHZ GDAFEMHZ
中序遍历: A D E F G H M Z ADEFGHMZ ADEFGHMZ

两个步骤:

  1. 根据前序中序,构造二叉树
  2. 后序遍历二叉树

前序遍历: G D A F E M H Z GDAFEMHZ GDAFEMHZ
中序遍历: A D E F G H M Z ADEFGHMZ ADEFGHMZ

  1. 根据前序遍历的特点得知,根结点为 G G G
  2. 根结点将中序遍历结果 A D E F G H M Z ADEFGHMZ ADEFGHMZ 分成 A D E F ADEF ADEF H M Z HMZ HMZ 两个左子树、右子树。
  3. 递归 确定中序遍历序列 A D E F ADEF ADEF 和前序遍历序列 D A E F DAEF DAEF 的子树结构;
  4. 递归确定中序遍历序列 H M Z HMZ HMZ 和前序遍历序列 M H Z MHZ MHZ 的子树结构;

显然问题的关键就是不断的找到各部分的根结点。

根据前序中序,构造二叉树
前序遍历: G D A F E M H Z GDAFEMHZ GDAFEMHZ
中序遍历: A D E F G H M Z ADEFGHMZ ADEFGHMZ

这里写图片描述

代码实现:

#include<stdio.h>
#include <stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;

void InPre2Post(const char* pInOrder, const char* pPreOrder, int nLength, char* pPostOrder, int& nIndex)
{
	if (nLength <= 0)
		return;
	if (nLength == 1)//长度为1,则直接把前序遍历的首字符作为后序遍历结果即可。
	{
		pPostOrder[nIndex] = *pPreOrder;
		nIndex++;
		return;
	}
	char root = *pPreOrder;//前序遍历首字符,也即是根结点
	int nRoot = 0;
	for (; nRoot < nLength; nRoot++)//查找根结点在中序遍历中的位置nRoot
	{
		if (pInOrder[nRoot] == root)
			break;
	}
	//后序遍历访问顺序:左右根
	InPre2Post(pInOrder, pPreOrder + 1, nRoot, pPostOrder, nIndex);//根结点的左子树部分再递归求,相当于访问左结点
	InPre2Post(pInOrder + nRoot + 1, pPreOrder + nRoot + 1, nLength - nRoot - 1, pPostOrder, nIndex);//根结点的右子树部分再递归求,相当于访问右结点
	pPostOrder[nIndex] = root;//访问根结点
	nIndex++;
}

int main()
{
	char pPreOrder[] = "GDAFEMHZ";
	char pInOrder[] = "ADEFGHMZ";
	int size = sizeof(pInOrder) / sizeof(char);
	char* pPostOrder = new char[size];
	int nIndex = 0;
	InPre2Post(pInOrder, pPreOrder, size - 1, pPostOrder, nIndex);
	pPostOrder[size - 1] = 0;
	cout << pPostOrder << endl;
	delete[] pPostOrder;
	return 0;
}

同理已知中序遍历还后序遍历求前序遍历,由后序遍历知道根结点,然后找到左子树右子树,再在各部分递归。问题的核心还是每次递归确定各部分的根结点。

#include<stdio.h>
#include <stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;

void InPost2Pre(const char* pInOrder, const char* pPostOrder, int nLength, char* pPreOrder, int& nIndex)
{
	if (nLength <= 0)
		return;
	if (nLength == 1)//长度为1,则直接把前序遍历的首字符作为后序遍历结果即可。
	{
		pPreOrder[nIndex] = *pPostOrder;
		nIndex++;
		return;
	}
	char root = *pPostOrder[size-1];//前序遍历首字符,也即是根结点
	//前序遍历访问顺序:根左右
	pPreOrder[nIndex]=root;
	nIndex++;
	int nRoot = 0;
	for (; nRoot < nLength; nRoot++)//查找根结点在中序遍历中的位置nRoot
	{
		if (pInOrder[nRoot] == root)
			break;
	}
	
	InPost2Pre(pInOrder, pPostOrder, nRoot, pPreOrder, nIndex);//根结点的左子树部分再递归求,相当于访问左结点
	InPost2Pre(pInOrder + nRoot + 1, pPostOrder + nRoot , nLength - nRoot - 1, pPreOrder, nIndex);//根结点的右子树部分再递归求,相当于访问右结点
}

int main()
{
	char pPostOrder[] = "AEFDHZMG";
	char pInOrder[] = "ADEFGHMZ";
	int size = sizeof(pInOrder) / sizeof(char);
	char* pPostOrder = new char[size];
	int nIndex = 0;
	InPost2Pre(pInOrder, pPostOrder, size - 1, pPreOrder, nIndex);
	pPostOrder[size - 1] = 0;
	cout << pPostOrder << endl;
	delete[] pPostOrder;
	return 0;
}

判断数组有无可能是二叉查找树后序遍历结果

给定整数数组,判断该数组有无可能是一颗***二叉查找树*** 后序遍历的结果。假定数组中***没有重复元素***。

由于后序遍历的最后一个元素为根结点,根据该结点,将数组分成前后两段,使得前半段都小于根结点,后半段都大于根结点;如果不存在这样的划分,则不可能是后序遍历的结果。递归判断前后半段是否满足同样的要求。

#include<stdio.h>
#include <stdlib.h>
#include<iostream>
#include<algorithm>
using namespace std;

bool CanPostOrder(const int*a, int size)
{
	if (size <= 1)
		return true;
	int root = a[size - 1];
	int nLeft = 0;
	while (nLeft<size-1)
	{
		if (a[nLeft] > root)
			break;
		nLeft++;
	}
	int nRight = size - 2;//size-1是根结点
	while (nRight>=0)
	{
		if (a[nRight] < root)
			break;
		nRight--;
	}
	if (nRight != nLeft - 1)//无法根据root分成两部分
		return false;

	return CanPostOrder(a, nLeft) && CanPostOrder(a + nLeft, size - nLeft - 1);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值