最全数据结构个人笔记【树-BST】

1.BST的基本概念

​ 二叉树的其中一个重要应用,就是提供一种快速查找数据的方法,即将数据节点按照某种规律形成一棵二叉树,然后利用二叉树特殊的逻辑结构减少搜索数据的次数,提高查找效率。这种按照某中规律构建,用来提高搜索性能的二叉树,被称为搜索二叉树(Binary Search Tree),即BST。

具体而言,二叉树提高搜索效率的秘诀在于:按照"小-中-大"(当然"大-中-小"也是一样)的规律来存储数据,即对于任意一个节点,都可以明确找到其值大于或等于其左孩子节点,且小于或等于其有孩子节点,如图所示:

在这里插入图片描述

由于树中所有的节点均满足,“小-中-大”的规律因此当从根开始查找某个节点时速度比顺序查找要快的多,比如要找节点38,当发现38大于根节点13后,就可以确定13的左子树一定没有38,这就去掉了半边子树的节点

因此二叉搜索树又称为二叉排序树、二叉查找树。

实际上,对于一棵二叉树而言,其搜索节点的时间复杂度,最糟糕的情形是其退化成链表,最乐观的情形是完全二叉树,那么其搜索时间复杂度就是介于: 最差 : T(n)=O(n) 最优 : T(n)=O(log2n)

2.插入节点

​ 对于BST而言,插入一个节点主要是要保持其"小-中-大"的逻辑不变,因此插入的的逻辑可以从根节点开始,一步一步寻找新节点的"最终归宿",比如在如下BST中,要插入新节点16,最终应该插入到节点17的左孩子处。

在这里插入图片描述

在实现插入算法的时候,由于树状结构本身是递归的,因此可以使用递归函数更优雅地实现插入算法。如下:

// 假设 BST 节点存储的数据类型是 int
node *newNode(int data)
{
    // 准备好新节点,并将数据填入其中
    node *new = (node *)malloc(sizeof(node));
    if(new != NULL)
    {
        new->data = data;
        new->lchild = NULL;
        new->rchild = NULL;
    }
    return new;
}

// 将新节点new插入到一棵以 root 为根的 BST 中
// 插入节点后,返回新的 BST 的根
node *bstInsert(node *root, node *new)
{
    // 若此时 BST 为空,则返回 new 使之成为二叉树的根节点
    if(root == NULL)
        return new;

    // 若新节点比根节点小,那么新节点应该插入左子树中
    // 至于插入到左子树的具体什么位置就不用管了,直接递归即可
    if(new->data < root->data)
        root->lchild = bstInsert(root->lchild, new);

    // 若新节点比根节点大,那么新节点应该插入右子树中
    // 至于插入到右子树的具体什么位置就不用管了,直接递归即可
    else if(new->data > root->data)
        root->rchild = bstInsert(root->rchild, new);

    // 若已存在,则不处理
    else
    {
        printf("%d已存在\n", new->data);
        free(new);
    }

    return root;
}

​ 「课堂练习3」

根据上述BST的插入算法,依次输入如下数据:8、3、1、6、4、7、10、14、13
创建如下二叉树:

在这里插入图片描述

提示:
为了检验创建出来的二叉树是否正确,可以使用如下代码将二叉树以网页形式展现出来:

  • drawtree.h
///
//
//  Copyright(C), 2013-2017, GEC Tech. Co., Ltd.
//
//  文件: lab/tree/headers/drawtree.h
//  日期: 2017-9
//  描述: 使用C语言写一页webpage展示二叉树
//
///

#ifndef _DRAWTREE_H_
#define _DRAWTREE_H_

/* ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 公共头文件 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
//#include <unistd.h>
#include <string.h>
//#include <strings.h>
#include <time.h>
#include <errno.h>
#include<unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>

// #include <sys/ipc.h>
// #include <sys/sem.h>
// #include <sys/shm.h>
// #include <sys/msg.h>
// #include <semaphore.h>
#include <fcntl.h>

//#include <pthread.h>
/* ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 公共头文件 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ */

#define MAX(a, b) ({ \
		typeof(a) _a = a; \
		typeof(b) _b = b; \
		(void)(&_a == &_b);\
		_a > _b? _a : _b; \
		})


/* ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 默认二叉树节点 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */
typedef struct _tree_node
{
	int data;
	struct _tree_node *lchild;
	struct _tree_node *rchild;

#ifdef AVL
	int height;
#endif

#ifdef RB
	struct _tree_node *parent;
	int color;
#endif
}_treenode, *_linktree;
/* ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ 默认二叉树节点 ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ */


/* ↓↓↓↓↓ 用户指定二叉树节点 ↓↓↓↓↓ */
#ifndef NODE
#define NODE _treenode
#endif
/* ↑↑↑↑↑ 用户指定二叉树节点 ↑↑↑↑↑ */



/* ↓↓↓↓↓↓↓↓↓↓↓↓↓ 画网页相关算法代码 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */

#ifndef QUEUE_NODE_DATATYPE
#define QUEUE_NODE_DATATYPE NODE *
#endif

typedef QUEUE_NODE_DATATYPE qn_datatype;

struct _queue_node
{
	qn_datatype data;
	struct _queue_node *next;

};

typedef struct
{
	struct _queue_node *front;
	struct _queue_node *rear;
#ifdef QUEUE_SIZE
	int size;
#endif
}_queuenode, *_linkqueue;


static _linkqueue init_queue(void)
{
    _linkqueue q = (_linkqueue)malloc(sizeof(_queuenode));
	q->front = q->rear =
		(struct _queue_node *)malloc(sizeof(struct _queue_node));
	q->rear->next = NULL;

	return q;
}

static bool is_empty_q(_linkqueue q)
{
	return (q->front == q->rear);
}

/* ↓↓↓↓↓↓↓↓↓↓↓↓↓ 画网页相关算法代码 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */
static bool out_queue(_linkqueue q, qn_datatype *pdata)
{
	if(is_empty_q(q))
		return false;

	struct _queue_node *p = q->front;

	q->front = q->front->next;
	free(p);
	*pdata = q->front->data;

	return true;
}

static bool en_queue(_linkqueue q, qn_datatype data)
{
	struct _queue_node *pnew;
	pnew = (struct _queue_node *)malloc(sizeof(struct _queue_node));
	if(pnew == NULL)
		return false;

	pnew->data = data;
	pnew->next = NULL;

	q->rear->next = pnew;
	q->rear = pnew;

	return true;
}

#ifdef QUEUE_SIZE
int queue_size(_linkqueue *q)
{
	return q->size;
}
#endif
/* ↓↓↓↓↓↓↓↓↓↓↓↓↓ 画网页相关算法代码 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */


static void pre_travel(NODE *root, void (*handler)(NODE *))
{
	if(root == NULL)
		return;
	
	handler(root);
	pre_travel(root->lchild, handler);
	pre_travel(root->rchild, handler);
}

static void mid_travel(NODE *root, void (*handler)(NODE *))
{
	if(root == NULL)
		return;
	
	mid_travel(root->lchild, handler);
	handler(root);
	mid_travel(root->rchild, handler);
}

static void post_travel(NODE *root, void (*handler)(NODE *))
{
	if(root == NULL)
		return;

	post_travel(root->lchild, handler);
	post_travel(root->rchild, handler);
	handler(root);
}

/* ↓↓↓↓↓↓↓↓↓↓↓↓↓ 画网页相关算法代码 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */
static void level_travel(NODE *root, void (*handler)(NODE *))
{
	if(root == NULL)
		return;

    _linkqueue q;
	q = init_queue();

	en_queue(q, root);

    NODE *tmp;
	while(1)
	{
		if(!out_queue(q, &tmp))
			break;

		handler(tmp);

		if(tmp->lchild != NULL)
			en_queue(q, tmp->lchild);
		if(tmp->rchild != NULL)
			en_queue(q, tmp->rchild);
	}
}
/* ↓↓↓↓↓↓↓↓↓↓↓↓↓ 画网页相关算法代码 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */
static char page_begin[] = "<html><head><title>tree map"
                           "</title></head><body>"
			   "<table border=0 cellspacing"
                           "=0 cellpadding=0>";
static char line_begin[] = "<tr>";
static char line_end  [] = "</tr>";
static char space     [] = "<td>&nbsp;</td>";
static char underline [] = "<td style=\"border-bottom:"
	 		   "1px solid #58CB64\">&nbsp;"
                           "</td>";

#ifdef RB
static char data_begin_red[] = "<td bgcolor=\"#FF0000\";style="
			       "\"border:1px sol"
                               "id #58CB64;background-colo"
                               "r:#DDF1D8;PADDING:2px;\" t"
                               "itle=\"level: 1\">";
static char data_begin_blk[] = "<td bgcolor=\"#000000\";style="
			       "\"border:1px sol"
                               "id #58CB64;background-colo"
                               "r:#DDF1D8;PADDING:2px;\" t"
                               "itle=\"level: 1\"><font color"
				"=\"#FFFFFF\">";
static char data_end_red[] = "</td>";
static char data_end_blk[] = "</font></td>";
#else
static char data_begin[] = "<td style=\"border:1px sol"
                           "id #58CB64;background-colo"
                           "r:#DDF1D8;PADDING:2px;\" t"
                           "itle=\"level: 1\">";
static char data_end  [] = "</td>";
#endif

static char page_end  [] = "</table></body></html>";

#define MAX_NODES_NUMBER 100
#define FILENAME 32

static int central_order[MAX_NODES_NUMBER];

static void putunderline(int fd, int num)
{
	int i;
	for(i=0; i<num; i++)
	{
		write(fd, underline, strlen(underline));
	}
}


static void putspace(int fd, int num)
{
	int i;
	for(i=0; i<num; i++)
	{
		write(fd, space, strlen(space));
	}
}
/* ↓↓↓↓↓↓↓↓↓↓↓↓↓ 画网页相关算法代码 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */
#ifdef RB
static void putdata(int fd, NODE * p)
{
	char s[50];
	bzero(s, 50);

	snprintf(s, 50, "%d", p->data);

	switch(p->color)
	{
	case RED:
		write(fd, data_begin_red, strlen(data_begin_red));
		write(fd, s, strlen(s));
		write(fd, data_end_red, strlen(data_end_red));
		break;
	case BLACK:
		write(fd, data_begin_blk, strlen(data_begin_blk));
		write(fd, s, strlen(s));
		write(fd, data_end_blk, strlen(data_end_blk));
	}
}
#else
static void putdata(int fd, int data)
{
	char s[50] = {0};
	//bzero(s, 50);

	snprintf(s, 50, "%d", data);
	write(fd, data_begin, strlen(data_begin));
	write(fd, s, strlen(s));
	write(fd, data_end, strlen(data_end));
}
#endif

static int Index = 0;
static void create_index(NODE * root)
{
	if(Index >= MAX_NODES_NUMBER-1)
		return;

	central_order[Index++] = root->data;
}


static int get_index(int data)
{
	int i;
	for(i=0; i<100; i++)
	{
		if(central_order[i] == data)
			return i;
	}
	return -1;
}

/* ↓↓↓↓↓↓↓↓↓↓↓↓↓ 画网页相关算法代码 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */
static void data_leftside(int fd, NODE * root, int spaces)
{
	if(root == NULL)
		return;

	int s_line=0;

	if(root->lchild != NULL)
	{
		s_line = get_index(root->data)-
			 get_index(root->lchild->data)-1;
	}
	putspace(fd, spaces-s_line);
	putunderline(fd, s_line);
}


static int data_rightside(int fd, NODE * root)
{
	if(root == NULL)
		return 0;

	int s_line=0;

	if(root->rchild != NULL)
	{
		s_line = get_index(root->rchild->data)-
			 get_index(root->data)-1;
	}

	putunderline(fd, s_line);
	return s_line;
}


static void start_page(int fd)
{
	write(fd, page_begin, strlen(page_begin));
}

/* ↓↓↓↓↓↓↓↓↓↓↓↓↓ 画网页相关算法代码 ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ */
static void end_page(int fd)
{
	write(fd, page_end, strlen(page_end));
}

// 显示
static void draw(NODE * root)
{
	if(root == NULL)
		return;

	time_t t;
	time(&t);
	static char filename[FILENAME] = {0};
	//bzero(filename, FILENAME);
	snprintf(filename, FILENAME, "%u.html", (unsigned)t);
	int fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0644);
	if(fd == -1)
	{
		perror("open() failed");
		exit(1);
	}

	Index = 0;
	mid_travel(root, create_index);

    _linkqueue q = init_queue();

	NODE * tmp = root;
	int ndata = 1;

	start_page(fd);
	while(1)
	{
		write(fd, line_begin, strlen(line_begin));

		int i, n = 0;
		int nextline = 0;
		for(i=0; i<ndata; i++)
		{
			int index = get_index(tmp->data);

			data_leftside(fd, tmp, index-n);

			#ifdef RB
			putdata(fd, tmp);
			#else
			// 如果想要在网页上显示字符,将putdata函数里面的sprintf()的%d换成%c
			putdata(fd, tmp->data);
			#endif
			int rightline = data_rightside(fd, tmp);

			if(tmp->lchild != NULL)
			{
				nextline++;
				en_queue(q, tmp->lchild);
			}
			if(tmp->rchild != NULL)
			{
				nextline++;
				en_queue(q, tmp->rchild);
			}
			if(!out_queue(q, &tmp))
				return;

			n = index + rightline;
			n++;
		}
		write(fd, line_end, strlen(line_end));
		ndata = nextline;
	}
	end_page(fd);
	close(fd);
}
#endif

#define TREENODE node // 声明自定义的二叉树节点为TREENODE
#include "drawtree.h" // 包含画树代码

int main()
{
    ...

    // 以网页形式展现二叉树
    draw(root);
}

其中,node是自己定义的二叉树的节点的类型,在包含 drawtree.h 之前定义 TREENODE 这个宏为 node ,即可展示对应二叉树。

在这里插入图片描述

遍历代码

以上述练习中的二叉树为例,采用前、中、后序遍历的算法示例代码如下:

// 前序遍历
void preOrder(node *root)
{
    if(root == NULL)
        return;

    // 先访问根节点
    printf("%d", root->data);

    // 再依次使用前序算法,遍历其左、右子树
    preOrder(root->lchild);
    preOrder(root->rchild);
}

「课堂练习4」

将下面这棵二叉树,按照前序、中序、后序方式,编程实现输出其各个节点的值。

在这里插入图片描述

// 先序遍历
void pre_order(BSTNode *root)
{
    if(root == NULL)// 叶子节点
        return;
    printf("%d\t",root->data);
    // 遍历左子树,作为root节点
    pre_order(root->lchild);
    // 遍历右子树,作为root节点
    pre_order(root->rchild);
}

// 中序遍历
void mid_order(BSTNode *root)
{
    if(root == NULL)
        return;

    // 先遍历左子树
    mid_order(root->lchild);
    // 输出根节点
    printf("%d\t",root->data);
    // 遍历右子树
    mid_order(root->rchild);
}

// 后序遍历
void post_order(BSTNode *root)
{
    if(root == NULL)
        return;

    // 先遍历左子树
    post_order(root->lchild);
    // 遍历右子树
    post_order(root->rchild);
    // 输出根节点
    printf("%d\t",root->data);
}

删除节点

删除一个BST的节点要比插入困难一点,但同样是要遵循一个原则,即:删除节点后仍然要保持“小-中-大”的逻辑关系。

非递归思路

在这里插入图片描述

// 创建新节点
BSTNode *CreateNode(dataType data)
{
    BSTNode *pnew = malloc(sizeof(BSTNode));
    if (pnew == NULL)
        return NULL;

    pnew->data = data;
    pnew->lchild = NULL;
    pnew->rchild = NULL;

    return pnew;
}


//非递归——删除
BSTNode *DeleteNode(BSTNode *root,dataType d)
{
    //查找
    BSTNode *p = root;//遍历指针
    BSTNode *pF = NULL;     //指向p节点的父节点pF

    while (p)
    {
        if( d == p->data )  // 找到需要剔除的节点
            break;
        else if (d < p->data)     // 从左子树继续找
        {
            pF = p;
            p = p->lchild;
        }
        else 
        {
            pF = p ;
            p = p->rchild;
        }
        
    }
    
    // 找不到
    if(p == NULL)
        return root;

    //删除
Delete:
    //1—— p没有孩子
    if(p->lchild == NULL && p->rchild == NULL)    //p无孩子
    {
        //无父节点
        if(pF == NULL)  //删除的就是根节点,且这棵树只有一个节点
        {
            free(p);
            root = p = NULL;
            return NULL;
        }
        //有父结点  
        else if(pF ->lchild == p)   //p是pF左孩子
        {
            pF->lchild = NULL;
            free(p);
            p = NULL;
        }
        else                   //p是pF右孩子
        {
            pF->rchild = NULL;
            free(p);
            p = NULL;
        }
    }
    //2—— p有1个孩子
    else if(p->lchild != NULL && p->rchild == NULL)   //有左子节点
    {
         //有无父节点
        if(pF == NULL)  //删除的就是根节点
        {
            root = p->lchild;
            p->lchild = NULL;
            free(p);
            p = NULL;
        }
 
        else if(pF ->lchild == p)   //p是pF左孩子
        {
           pF->lchild = p->lchild;
           p ->lchild = NULL;
           free(p);
           p = NULL;
        }
        else if(pF ->rchild == p)   //p是pF右孩子
        {
            pF->rchild = p->lchild;
            p ->lchild = NULL;
            free(p);
            p = NULL;
        }
    }
    else if(p->lchild == NULL && p->rchild != NULL)   //有右子节点
    {
        //有无父节点
        if(pF == NULL)  //删除的就是根节点
        {
            root = p->rchild;
            p->rchild = NULL;
            free(p);
            p = NULL;
        }
 
        else if(pF ->lchild == p)   //p是pF左孩子
        {
           pF->lchild = p->rchild;
           p ->rchild = NULL;
           free(p);
           p = NULL;
        }
        else if(pF ->rchild == p)   //p是pF右孩子
        {
            pF->rchild = p->rchild;
            p ->rchild = NULL;
            free(p);
            p = NULL;
        }
    }

    //3—— p有2个孩子
    else    
    {   //左子树中找最大 或者 右子树中找最小
        BSTNode *pK = p->lchild;    //pK去左子树中找最大

        // 找p的左子树最大值pK
        // 如果pK的右孩子为空,表示pK为p左子树的最大节点
        while (pK->rchild)
        {
            pF = pK;
            pK = pK->rchild;
        }
        //此时pK所在位置就是替换位置
        
        //pK为p的左孩子
        if(pK  == p->lchild)
        {
            // p和pK交换删除pK
            p->data = pK->data;
            p->lchild = pK->lchild;
            pK->lchild = NULL;
            free(pK);
        }
        else
        {
            // p和pK交换删除pK
            p->data = pK->data;
            pF->rchild = pK->lchild;
            pK->lchild = NULL;
            free(pK); 
        }

    }
    return root;
}


// 将一个节点插入到BST树
BSTNode *InsertNode(BSTNode *root, dataType data)
{
    // 创建节点
    BSTNode *pnew = CreateNode(data);
    if (pnew == NULL)
    {
        printf("Memory allocation failed\n");
        return root;
    }

    // 遍历指针p
    BSTNode *p = root;
    // 从无到有
    if (root == NULL)
    {
        root = pnew;
    }
    else // 从少到多
    {
        while (1)
        {
            if (p->data > data) // 插入左子树
            {
                if (p->lchild == NULL) // 有位置插入
                {
                    p->lchild = pnew;
                    break;
                }
                else // 接着往下找
                    p = p->lchild;
            }
            else if (p->data < data) // 插入右子树
            {
                if (p->rchild == NULL)
                {
                    p->rchild = pnew;
                    break;
                }
                else
                    p = p->rchild;
            }
            else
            {
                printf("insert data failed:\n");
                free(pnew);
                break;
            }
        }
    }

    return root;

}

// 创建BST树
BSTNode *CreateBST(void)
{
    BSTNode *root = NULL;
    dataType data;
    while (1)
    {
        if (scanf("%d", &data) == 0)
        {
            while (getchar() != '\n');
            break;
        }

        root = InsertNode(root, data);
    }

    return root;
}

//前序遍历
void PreOrder(BSTNode *root)
{
    if(root == NULL)
        return ;
    
    //先访问根节点
    printf("  %d  ",root->data);
    PreOrder(root->lchild);
    PreOrder(root->rchild);
}

//中序遍历
void MidOrder(BSTNode *root)
{
    if(root == NULL)
        return ;
    

    MidOrder(root->lchild);
    printf("  %d  ",root->data);
    MidOrder(root->rchild);

}

//后序遍历
void PostOrder(BSTNode *root)
{
    if(root == NULL)
        return ;

    PostOrder(root->lchild);
    PostOrder(root->rchild);
    printf("  %d  ",root->data);
}

/*
    LevelTravel:    对一棵二叉排序树进行层次遍历
*/
void LevelTravel(BSTNode *root)
{
    printf("LevelTravel:");
    if (root == NULL)
        return;
    //创建队列
    LinkedQueue *q = InitQueue();                   // 初始
    if(q==NULL)
        return;

    //根节点入队
    EnQueue(q,root);

    while (!IsEmpty(q))
    {
        //出队
        QElemType d;
        DeQueue(q,&d);
        printf("  %d  ",d->data);

        //出队元素的孩子节点入队
        if(d->lchild)
            EnQueue(q,d->lchild);
        if(d->rchild)
            EnQueue(q,d->rchild);
    }
    
    //销毁队列
    DestroyQueue(q);
    printf("\n");
}

/*
    LevelTravel:    求一棵二叉排序树深度
*/
int GetDepth(BSTNode*root)
{
    if(root == NULL)
        return 0;
    int L = GetDepth(root->lchild);
    int R = GetDepth(root->rchild);
    return L > R ? L+1 : R+1;
}

递归思路

假设要删除的节点是x,大体思路如下:

  1. 若要删除的节点小于根节点,则递归地在左子树中删除x

  2. 若要删除的节点大于根节点,则递归地在右子树中删除x

  3. 若要删除的节点恰好就是根节点,则分如下几种情况:
    a. 根节点若有左子树,则用左子树中最大的节点max替换根节点,并在左子树中递归删除max
    b. 否则,若有右子树,则用右子树中最小的节点min替换根节点,并在右子树中递归删除min
    c. 否则,直接删除根节点

以下图为例,假设在一棵二叉树中要删除节点15,在找到节点之后,判断其有左子树,那么就沿着其左子树找到最右下角(最大)的节点19,替换要删除的节点15,然后再将多余的节点19删掉:

在这里插入图片描述

删除一个有左子树的节点过程

而如果要删除的节点没有左子树,只有右子树,那么情况是完全对称的,如下图所示,假设要删除节点25,由于25没有左子树,因此找到其右子树中最左下角(最小)的节点16,替换要删除的节点25,然后再将多余的节点16删掉:

在这里插入图片描述

删除一个只有右子树的节点过程

代码如下:

// 将数据(以整型为例)data从二叉树中删除
// 并返回删除之后的二叉树的根
node *bstRemove(node *root, int data)
{
    if(root == NULL)
        return NULL;

    // 若data小于根节点,则递归地在左子树中删除它
    if(data < root->data)
        root->lchild = bstRemove(root->lchild, data);

    // 若data小于根节点,则递归地在左子树中删除它
    else if(n > root->data)
        root->rchild = bstRemove(root->rchild, data);

    // 若data恰好就是根节点,则分如下几种情况:  
    else
    {
        // a. 根节点若有左子树,则用左子树中最大的节点max替换根节点
        //    并在左子树中递归删除max  
        if(root->lchild != NULL)
        {
            node *max;
            for(max=root->lchild; max->rchild!=NULL;
                max=max->rchild);

            root->data = max->data;
            root->lchild = bstRemove(root->lchild, max->data);
        }

        // b. 否则,若有右子树,则用右子树中最小的节点min替换根节点
        //    并在右子树中递归删除min  
        else if(root->rchild != NULL)
        {
            for(tmp=root->rchild; tmp->lchild!=NULL;
                tmp=tmp->lchild);

            root->data = tmp->data;
            root->rchild = bst_remove(root->rchild, tmp->data);
        }

        // c. 否则,直接删除根节点
        else
        {
            free(root);
            return NULL;
        }
    }

    return root;
}

data = max->data;
root->lchild = bstRemove(root->lchild, max->data);
}

    // b. 否则,若有右子树,则用右子树中最小的节点min替换根节点
    //    并在右子树中递归删除min  
    else if(root->rchild != NULL)
    {
        for(tmp=root->rchild; tmp->lchild!=NULL;
            tmp=tmp->lchild);

        root->data = tmp->data;
        root->rchild = bst_remove(root->rchild, tmp->data);
    }

    // c. 否则,直接删除根节点
    else
    {
        free(root);
        return NULL;
    }
}

return root;

}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值