C语言实现链式结构二叉树的相关函数

本文介绍如何用C语言实现链式结构的二叉搜索树,特别是节点删除功能。通过非递归的前中后序遍历,并讨论了在节点有两个孩子时的删除策略,选择将左子树的最大节点替换待删除节点。
摘要由CSDN通过智能技术生成

自己画个图, 然后看代码。这样会容易上手。
这个帖子会持续修改的。
下面的树是链式结构实现的。
下面的所有程序基本都通过Ubuntu上gdb调试验证过,如果还是有错,麻烦指出一下,谢谢
非递归的前中后序遍历函数中创建动态堆栈函数中的mallo函数似乎有问题

如果要被删除的节点有两个孩子节点,有两种方案:
① 将其左子树的最大节点,替换要删除的节点
② 将其右子树的最小节点, 替换要删除的节点
下面的函数选择的是方案①

/********************************************************************************
* Copyright(c) 2019-20xx
* All right resered.
*
* @file  	binary_tree.h
* @author 	hongsmallgod
* @version	V1.0.1
* @data		2019-9-17 10:29:20
* @brief	二叉树头文件
********************************************************************************/
#ifndef _BINARY_TREE_H
#define _BINARY_TREE_H
#include <stdbool.h>
typedef struct tree_node binary_tree, tree;
struct tree_node {
    int data;
    tree *left;
    tree *right;
};

extern int create_tree(tree **node);
extern tree *find_ordered(tree *root, int key);
extern void destroy_tree(tree *root);
extern tree *find_unordered(tree *root, int key);
extern void pre_order_traversal(tree *bt);
extern bool delete_tree_node(tree *root, int key);
extern int get_tree_node_num(tree *root);
extern int tree_depth(tree *root);
extern int tree_insert(tree **root, int data);
extern void pre_order_traversal(tree *bt);
extern void in_order_traversal(tree *bt);
extern void post_order_traversal(tree *bt);
extern void level_order_traversal(tree *root);
#endif
/********************************************************************************
* Copyright(c) 2019-20xx
* All right resered.
*
* @file  	binary_tree.c
* @author 	hongsmallgod
* @version	V1.0.1
* @data		2019-9-17 10:29:20
* @brief	二叉树源文件
********************************************************************************/
#include <stdio.h>       /* FOR scanf() */
#include <stdlib.h>
#include "dynamic_stack.h"
#include "binary_tree.h"
#include "chain_queue.h"
#define MAX_STACK_SIZE 1024

/*
** function  : create_tree
** author    : hongsmallgod
** brief     : 按前序遍历创建二叉树,节点为NULL时, 输入 -1
**             完全二叉搜索树(4 2 1 -1 -1 3 -1 -1 6 5 -1 -1 7 -1 -1)
** argument  : @node: 根节点指针的指针
** return    : 1: 创建成功; -1: 创建失败; 0: 结束当前节点的创建
*/
int create_tree(tree **node)
{
    *node = (tree *)calloc(1, sizeof(tree));
    if (*node == NULL)
        return -1;
    if (scanf("%d", &(*node)->data) != 1 || (*node)->data == -1) {
        free(*node);
        *node = NULL;
        return 0;
    }
    if (-1 == create_tree(&(*node)->left)) {
		free(*node);
		*node = NULL;
		return -1;
	}
    
    if (-1 == create_tree(&(*node)->right)) {
		destroy_tree(*node);
		*node = NULL;
		return -1;
	}
    return 1;
}

/*
** function  : find_ordered
** author    : hongsmallgod
** brief     : 有序二叉树的查找
** argument  : @root: 根节点指针; @key: 查找的关键值
** return    : NULL: 没有找到; else: 节点的地址
*/
tree *find_ordered(tree *root, int key)
{
    tree *current = root;
    while (current) {
        if (current->data > key)
            current = current->left;
        else if (current->data < key)
            current = current->right;
        else
            break;
    }
    return current;
}

/*
** function  : destroy_tree
** author    : hongsmallgod
** brief     : 把整颗二叉树给销毁掉
** argument  : @root: 根节点指针
** return    : none
*/
void destroy_tree(tree *root)
{
    if (root) {
        destroy_tree(root->left);
        root->left = NULL;
        destroy_tree(root->right);
        root->right = NULL;
        free(root);
    }
}

/*
** function  : find_unordered
** author    : hongsmallgod
** brief     : 无序二叉树的查找
** argument  : @root: 根节点指针; @key: 查找的关键值
** return    : NULL: 没有找到; else: 节点的地址
*/
tree *find_unordered(tree *root, int key)
{
    tree *ret = NULL;
    if (root) {
        if (root->data == key)
            return root;
        ret = find_unordered(root->left, key);
        if (ret)
            return ret;
        ret = find_unordered(root->right, key);
        if (ret)
            return ret;
    }
    return NULL;
}

/*
** function  : pre_order_traversal
** author    : hongsmallgod
** brief     : 二叉树的前序遍历
** argument  : @bt: 根节点指针
** return    : none
*/
void pre_order_traversal(tree *bt)
{
	binary_tree *t = bt;
    stack *s = create_stack(MAX_STACK_SIZE);
#if 0 /* 前面这部分是自实现的, 后面的是MOOC上的数据结构课程的 */
    while (1) {
        while (t) {
            s->push(s, t);
            printf("%d ", t->data);
            t = t->left;
        }

        if (s->empty(s)) /* 什么情况下堆栈会为空 */
            break;
        s->pop(s, &t);
        t = t->right;
    }
#else
	while (t || !s->empty(s)) {
		while (t) {
			s->push(s, t);
			printf("%d ", t->data);
			t = t->left;
		}
		
		if (!s->empty(s)) {
			s->pop(s, &t);
			t = t->right;
		}
	}
#endif
	printf("\n");
	destory_stack(s);
}

/*
** function  : in_order_traversal
** author    : hongsmallgod
** brief     : 二叉树的中序遍历
** argument  : @bt: 根节点指针
** return    : none
*/
void in_order_traversal(tree *bt)
{
    binary_tree *t = bt;
    stack *s = create_stack(MAX_STACK_SIZE);
    while (t || !s->empty(s)) {
        while (t) {
            s->push(s, t);
            t = t->left;
        }

        if (!s->empty(s)) {
            s->pop(s, &t);
            printf("%d ", t->data);
            t = t->right;
        }
    }
    printf("\n");
    destory_stack(s);
}

/*
** function  : post_order_traversal
** author    : hongsmallgod
** brief     : 二叉树的后序遍历
** argument  : @bt: 根节点指针
** return    : none
*/
void post_order_traversal(tree *bt)
{
    binary_tree *t = bt;
    stack *s = create_stack(MAX_STACK_SIZE);
    /*
    ** 前面的这个是自己想到的(感觉违反了后续遍历的定义 ), 后面的是慕课数据结构
    ** 课程的讨论环节的个别讨论评论
    */
#if 0
    while (t || !s->empty(s)) {
        while (t) {
            s->push(s, t);
            printf("%d ", t->data);
            t = t->right;
        }

        if (!s->empty(s)) {
            s->pop(s, &t);
            t = t->left;
        }
    }
#else
    tree *pre = NULL;
    while ((t || !s->empty(s)) && pre != bt) {
        while (t) {
            s->push(s, t); 
            t = t->left;
        }

        while (!s->empty(s)) {
            s->pop(s, &t);
            if (t->right == pre || t->right == NULL) {
                printf("%d ", t->data);
                pre = t;
            } else {
                s->push(s, t);
                t = t->right;
                break;
            }
        }
    }
#endif
	printf("\n");
    destory_stack(s);
}

/*
** function  : level_order_traversal
** author    : hongsmallgod
** brief     : 二叉树的后序遍历
** argument  : @root: 根节点指针
** return    : none
*/
void level_order_traversal(tree *root)
{
    queue *q = create_queue();
    do {
        if (root) {
            printf("%d ", root->data);
            if (root->left)
                q->enqueue(q, root->left);
            if (root->right)
                q->enqueue(q, root->right);
        }
        if (q->empty(q))
            break;
        q->dequeue(q, &root);
    } while (1);
	printf("\n");
    destroy_queue(q);
}

/*
** function  : delete_tree_node
** author	 : hongsmallgod
** brief     : 根据关键值, 删除二叉树节点
** argument  : @root: 根节点指针; @key: 关键值
** return 	 : true: 删除成功; false: 删除失败
*/
bool delete_tree_node(tree *root, int key)
{
	tree *current = root;	/* 变量名可读性 */
	tree **pre = NULL;    	/* 保存指向当前节点指针的指针 */

	while (current) {
		if (current->data < key) {
			pre = &current->right;
			current = current->right;
		} else if (current->data > key) {
			pre = &current->left;
			current = current->left;
		} else {
			break;
		}
	}

	/*
	**  没找到对应节点
	*/
	if (NULL == current)
		return false;
	/*
	**  获取孩子节点数
	*/
	int child_num = 0;
	if (current->left)
		child_num++;
	if (current->right)
		child_num++;
	
	/*
	**  根据current节点的孩子节点数, 分三种情况:
	*/
	switch (child_num) {
	case 0:
		*pre = NULL;
		break;

	case 1:
		if (current->left)
			*pre = current->left;
		else
			*pre = current->right;
		break;

	case 2:
		/*
		**  删除其左子树中关键值最大的节点,并将其节点的内容赋值到当前节点
		*/
		{
			tree **pre = NULL;
			tree *this = current;
			
			pre = &this->left;	/* 调试代码时, 发现遗漏了这一句 */
			this = this->left;
			while (this->right) {
				pre = &this->right;
				this = this->right;
			}

			*pre = NULL;
			current->data = this->data;

			free(this);
			this = NULL;
		}
	break;

	default :
		/* 机器在非正常情况下, 会跑这里 */
		exit(EXIT_FAILURE);
		break;
	}
	return true;
}

/*
** function  : get_tree_node_num
** author	 : hongsmallgod
** brief     : 获取树节点数量
** argument  : @root: 树根节点指针
** return 	 : 节点数
*/
int get_tree_node_num(tree *root)
{
    int count = 0;
    if (root) {
        count++;
        count += get_tree_node_num(root->left);
        count += get_tree_node_num(root->right);
    }
    return count;
}

/*
** function  : tree_depth
** author	 : hongsmallgod
** brief     : 求树的最大深度
** argument  : @root: 树根节点指针
** return 	 : 节点数
*/
int tree_depth(tree *root)
{
    if (root) {
        int left_depth = tree_depth(root->left);
        int right_depth = tree_depth(root->right);
        return left_depth > right_depth ? left_depth + 1 : right_depth + 1;
    }
    return 0;
}

/*
** function  : tree_insert
** author	 : hongsmallgod
** brief     : 二叉搜索树的插入
** argument  : @root: 树根节点指针的指针; @data: 要插入的数据
** return 	 : 1: 插入成功; 0:有相同的值,插入失败; -1: 内存不足
*/
int tree_insert(tree **root, int data)
{
    tree *current = *root;
    tree **pre = root;
    /*
    ** 寻找要插入的位置
    */
    while (current) {
        if (data > current->data) {
            pre = &current->right;
            current = current->right;
        } else if (data < current->data) {
            pre = &current->left;
            current = current->left;
        } else {
            return 0;
        }
    }

    current = (tree *)calloc(1, sizeof(tree));
    if (NULL == current)
        return -1;
    current->data = data;
    *pre = current;
    return 1;
}

/*
**  递归的前序、中序、后序遍历
*/
void pre_order_traversal(tree *bt)
{
	if (bt) {
		printf("%d ", bt->data);
		pre_order_traversal(bt->left);
		pre_order_traversal(bt->right);
	}
}

void in_order_traversal(tree *bt)
{
	if (bt) {
		in_order_traversal(bt->left);
		printf("%d ", bt->data);
		in_order_traversal(bt->right);
	}
}

void post_order_traversal(tree *bt)
{
	if (bt) {
		post_order_traversal(bt->left);
		post_order_traversal(bt->right);
		printf("%d ", bt->data);
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值