二叉树操作算法

二叉搜索树转化为双向链表

void _revertToDoubleList(struct node *root, struct node** prev ) {
	if (root == NULL) {
		return;
	}

	revertToDoubleList(root->left, prev);
	root->left = *prev;
	if (prev != NULL && *prev != NULL)
		(*pre)->right = root;
	*pre = root;
	revertToDoubleList(root->right, prev); 
}

struct node * revertToDoubleList(struct node *root) {
	if (root == NULL)
		return NULL;

	struct node *prev = NULL;
	_revertToDoubleList(root, prev);

	struct node *head = root, *tail = root;
	while (tail->right != NULL) {
		tail = tail->right;
	}

	head->left = tail;
	tail->right = head;

	return head;
}


二叉树翻转

struct node * reverseTree(struct node *root)
{
	if (root == NULL) {
		return NULL;
	}
	struct node *left = node->left;
	struct node *right = node->right;
	
	root->left = right;
	root->right = left;
	
	reverseTree(left);
	reverseTree(right);
}

最近公共节点

出口

  1. 没有找到a或b,则返回NULL;
  2.  碰到a或b,就立刻返回

实现

struct node* findLowestCommonAncestor(struct node* root, struct node *node1, struct node *node2) {
	if (root == NULL)
		return NULL;

	if (root == node1 || root == node2) {
		return root;
	}

	sturct node *left = findLowestCommonAncestor(root->left, node1, node2);
	sturct node *right = findLowestCommonAncestor(root->right, node1, node2);

	if (left && right)
		return root;
	return left? left:right;
}

比较两棵二叉树

int compare(struct node *node2, struct node*node1) {
	if (node2 == node1) {
		if (node1 == NULL) {
			return 1;
		} else {
			return compare(node1->left, node2->left) && 
				compare(node1->right, node2->right);
		}
	}
	
	return 0;
}

获取二叉树的宽度

int getWidth(struct node *root)
{
	if (root == NULL) {
		return 0;
	}
	if (root->left == NULL && root->right == NULL) {
		return 1;
	} else {
		return getWidth(root->left) + getWidth(root->right);
	}
}

获取二叉树的高度

int getHeight(struct node *root)
{
	if (root == 0)
		return NULL;
	int left = getHeight(root->left);
	int right=getRight(root->right);
	
	return max(left, right) + 1;
}

二叉搜索树的后序遍历结果

思路

  • 二叉的特点为:左子树均小于当前节点,右子树均大于当前节点。

实现

bool verifySequeceOfBST(int *sequece, int start, int end)
{
    if (sequece == NULL ||start > end || start < 0 ||end < 0) {
        return false;
    }   
 
    bool left = true, right = true;
    int i = 0, middle = 0;
 
    while (i < end && sequece[i] <= sequece[end]) {
        i++;
    }   
    middle = i - 1;
 
    while (i < end  && sequece[i] > sequece[end]) {
        i++;
    }   
 
    if (i != end) {
        return false;
    }   
 
    if (middle > start) {
        left = verifySequeceOfBST(sequece, start, middle);
    }   
 
    if (middle < end - 1) {
        right = verifySequeceOfBST(sequece, middle + 1, end - 1); 
    }   
 
    return (left && right);
}

二叉树中和为某一值的所有路径

思路

  • 采用前序遍历的方式遍历树,利用vector来存储一条路径
  • 当遇到子节点的数值小于指定和,将当前节点加入路径,继续遍历;若大于指定和,则不需要继续遍历该棵子树的路径。
  • 当遇到叶子节点时,判断当前的路径和是否为指定的和,若为指定的和,则打印;
  • 遍历完左右子树后,需要将当前的节点从路径中删除。

算法实现

void printPath(vector<int> path)
{
    cout << "Path:>";
    for (vector<int>::iterator iter = path.begin(); iter != path.end(); iter++) {
        cout << *iter << " ";
    }   
    cout << endl;
}
 
void findFixedSumPath(BTreeNode<int> *root, int currentSum, int sum, vector<int>& path) {
    if (root == NULL) {
        return;
    }   
    currentSum += root->value;
    if (currentSum <= sum) {
        path.push_back(root->value);
    }   
    
    if (root->isLeaf() && currentSum == sum) {
        printPath(path);    
    }   
 
    findFixedSumPath(root->left, currentSum, sum, path);
    findFixedSumPath(root->right, currentSum, sum, path);
 
    path.pop_back();
}

有n个元素的完全二叉树的深度

完全二叉树:若设二叉树的高度为H,除第H层外,其它各层(1~H-1)的节点数都达到最大个数,第H层有叶子节点,并且叶子节点都是从左到右一次排布。判断方法:二叉树的所有子树要么没有孩子,要么一定有左孩子;二叉树要么没有子树,要么一定左右子树都有;

特点:叶子节点只可能在最大的两层上出现,对任意节点,若其右分支下的子孙最大层为L,则左分支下的子孙最大层为L或L+1

第i层最多有2^(i-1)个节点,共i层的完全二叉树最多有2^i - 1个节点。

前序遍历、中序遍历和后序遍历的互求方法

Answer:

一、已知前序、中序遍历,求后序遍历--结果唯一

例:前序遍历:GDAFEMHZ; 中序遍历:ADEFGHMZ

step1:由前序遍历可知G为root节点。

step2:由中序遍历得知:ADEF必为root的左子树,HMZ必然是root的右子树。

step3:观察左子树:ADEF。左子树的根节点,必为root的左子结点,而大树的左子结点紧接着G,故而D为左子树的根节点。

step4:同理可得M为右子树的根节点。

step5:根据上面过程递归得出:

    ① 确定根,确定左子树,确定右子树;

    ② 在左子树中递归

    ③ 在右子树中递归

    ④ 打印当前根

根据上述过程,可以画出二叉树的形状:

即后序遍历为:AEFDHZMG

二、已知中序和后序遍历,求前序遍历--结果唯一

例:中序遍历:ADEFGHMZ;后序遍历:AEFDHZMG

step1: 根据后序遍历的特点,可知最后一个节点为root节点,即root节点为G

step2:观察中序遍历,可知ADEF为左子树,HMZ为右子树

step3:观察左子树ADEF,在后序遍历中,左子树的根节点位于遍历的最后,故而D为根节点;同理可得,M为右子树的根节点;

step4:经过观察得出,确认子树的过程是递归的。递归过程如下:

    ① 确定根,确定左子树,确定右子树;

    ② 在左子树中递归

    ③ 在右子树中递归

    ④ 打印当前根

由此可得出前序遍历的结果为:GDAFEMHZ

三、已知前序遍历和后序遍历,求中序遍历--结果不唯一

二分搜索

int binary_search (int *data, int len, int key) 
{
    int left, right, middle;
    int ret = -1; 
 
    if (data == NULL || len <= 0) {
        return ret;
    }   
    left = 0;
    right = len;
    while (left < right) {
        middle = (left+right)/2;
 
        if (data[middle] < key) {
            left = middle+1;
        } else if (data[middle] > key) {
            right = middle;
        } else {
            return middle;
        }   
    }   
 
    return ret;
}

前序遍历


过程

  • 先遍历节点,在分别遍历左右子节点

方法

  1.  将root节点压栈;
  2. 循环直到栈为空:
    1. pop() 取出node
    2. 现将右子结点压栈,再将左子结点压栈----左子结点先出栈,先遍历!

代码实现

void prev_scan (node_t * node)
{
    struct stack *s = NULL;
    if (node == NULL)
        return;
   
    printf("prev_scan\n");
    s = create_stack();
    if (s == NULL) {
        printf("Create stack failed!\n");
        return;
    }
    push(&s, node);
    while (!is_empty(s)) {
        node = pop(&s);
        printf("%d\t", node->value);
        if (node->right) {
            push(&s, node->right);
        }
        if (node->left) {
            push(&s, node->left);
        }
    }
   
    printf("\n");
    destroy_stack(&s);
}

中序遍历

过程

  •     先遍历左子结点,在遍历节点,最后遍历右子结点

方法

  1. 循环将节点的左子结点压栈,直到左子结点为空
  2. 出栈,打印该节点
  3. 将该节点赋值为右子结点,继续循环。

代码实现

void mid_scan (node_t * node)
{
    struct stack *s = NULL;
    if (node == NULL)
        return;
 
    printf("mid_scan\n");
    s = create_stack();
    if (s == NULL) {
        printf("Create stack failed!\n");
        return;
    }
    while (node || !is_empty(s)){
        while (node) {
            push(&s, node);
            node = node->left;
        }   
 
        node = pop(&s);
        printf("%d\t", node->value);
        node = node->right;
    }   
    printf("\n");
    destroy_stack(&s);
}

后序遍历

过程

  • 先遍历左子结点,在遍历右子节点,最后遍历结点

方法

  1. 将该节点的左子结点循环压栈,直到左子结点为空;
  2. 查看当前栈顶元素:
    1.  若当前栈有右子结点,并且该右子节点没有打印过。则将该节点赋值为右子节点,继续1
    2. 若当前栈没有右子结点,或者右子节点已经打印过,则出栈,并打印该节点。然后对prev赋值为当前节点,cur赋值为null

代码实现

void post_scan (node_t * root)
{
    struct stack *s = NULL;
    node_t *prev = NULL, *cur = root;
    if (root == NULL)
        return;
    printf("post_scan\n");
    s = create_stack();
    if (s == NULL) {
        printf("Create stack failed!\n");
        return;
    }   
       
    while(cur || !is_empty(s)){
        while(cur) {
            push(&s,cur);
            cur = cur->left;
        }   
        cur = top(s);
        if (cur->right == NULL || cur->right == prev) {
            pop(&s);
            printf("%d\t", cur->value);
            prev = cur;
            cur = NULL;
        }else {
            cur = cur->right;
        }   
    }   
    printf("\n");
    destroy_stack(&s);
}

找出二叉树的深度

分析

  • 一个二叉树的深度等于max{左子树的深度,右子树的深度}+1

代码实现

struct node{
    int value;
    struct node *left;
    struct node *right;
};

int get_depth(struct node *root)
{
    int left = 0, right = 0 ;
    if(root == NULL){
        return 0;
    }

    left = get_depth(root->left);
    right = get_depth(root->right);

    return left > right? left+1: right+1;
}





  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值