一步一步写算法(之排序二叉树插入)

原文:一步一步写算法(之排序二叉树插入)

【 声明:版权所有,欢迎转载,请勿用于商业用途。  联系信箱:feixiaoxing @163.com】

二叉树的节点插入比较简单。一般来说,二叉树的插入主要分为以下两个步骤:

1) 对当前的参数进行判断,因为需要考虑到头结点,所以我们使用了指针的指针作为函数的输入参数

2) 分情况讨论:

如果原来二叉树连根节点都没有,那么这个新插入的数据就是根节点;

如果原来的二叉树有根节点,那我们判断这个数据是否存在过,如果存在,那么返回;如果不存在,那么继续插入数据。

那继续插入的数据怎么保存呢?又要分三种情况:

1)如果插入的数据小于当前节点的数据,那么往当前节点的左子树方向继续寻找插入位置

2)如果插入的数据大于当前插入的位置,那么往当前节点的右子树方向继续寻找插入位置

3)如果方向当前的节点为空,那么表示插入的位置找到了,插入数据即可

算法说了这么多,下面即开始练习我们的代码:

a)判断输入数据的合法性

STATUS insert_node_into_tree(TREE_NODE** ppTreeNode, int data)
{
	if(NULL == ppTreeNode)
		return FALSE;

	return TRUE;
}

此时,可以用一个测试用例验证一下

static void test1()
{
	assert(FALSE == insert_node_into_tree(NULL, 10));
}

b)判断当前根节点是否存在,修改代码

STATUS insert_node_into_tree(TREE_NODE** ppTreeNode, int data)
{
	if(NULL == ppTreeNode)
		return FALSE;

	if(NULL == *ppTreeNode){
		*ppTreeNode = (TREE_NODE*)create_tree_node(data);
		assert(NULL != *ppTreeNode);
		return TRUE;
	}

	return TRUE;
}

修改了代码,少不了测试用例的添加。

static void test2()
{
	TREE_NODE* pTreeNode = NULL;
	assert(TRUE == insert_node_into_tree(&pTreeNode, 10));
	assert(10 == pTreeNode->data);
	free(pTreeNode);
}

c)上面考虑了没有根节点的情况,那么如果根节点存在呢?

STATUS _insert_node_into_tree(TREE_NODE** ppTreeNode, int data, TREE_NODE* pParent)
{
	if(NULL == *ppTreeNode){
		*ppTreeNode = create_tree_node(data);
		assert(NULL != *ppTreeNode);
		(*ppTreeNode)->parent = pParent;
		return TRUE;
	}

	if(data < (*ppTreeNode)->data)
		return _insert_node_into_tree(&(*ppTreeNode)->left_child, data, *ppTreeNode);
	else
		return _insert_node_into_tree(&(*ppTreeNode)->right_child, data, *ppTreeNode);
}

STATUS insert_node_into_tree(TREE_NODE** ppTreeNode, int data)
{
	if(NULL == ppTreeNode)
		return FALSE;

	if(NULL == *ppTreeNode){
		*ppTreeNode = (TREE_NODE*)create_tree_node(data);
		assert(NULL != *ppTreeNode);
		return TRUE;
	}

	return _insert_node_into_tree(ppTreeNode, data, NULL);
}

上面的代码已经考虑了不是根节点的情况。我们可以据此添加一个测试用例。

static void test3()
{
	TREE_NODE* pTreeNode = NULL;
	assert(TRUE == insert_node_into_tree(&pTreeNode, 9));
	assert(TRUE == insert_node_into_tree(&pTreeNode, 8));
	assert(TRUE == insert_node_into_tree(&pTreeNode, 10));
	assert(9 == pTreeNode->data);
	assert(8 == pTreeNode->left_child->data);
	assert(10 == pTreeNode->right_child->data);
	free(pTreeNode->left_child);
	free(pTreeNode->right_child);
	free(pTreeNode);
}

由于上面的代码是递归代码,为了实现代码的健壮性和完毕性,其实我们设计测试用例的时候应该至少包括9个测试用例:

(1) 参数非法

(2) 根节点不存在

(3)根节点存在,但是插入的数据已经存在

(4)根节点存在,插入数据为 9, 8

(5)根节点存在, 插入数据为9, 10

(6)根节点存在,插入数据为9,8, 7

(7)根节点存在,插入数据为9,7,8

(8)根节点存在,插入数据为7,8, 9

(9)根节点存在,插入数据为7,9,8

【预告: 下面一篇博客主要介绍二叉树的节点删除】

时间: 2024-11-07 07:09:18

一步一步写算法(之排序二叉树插入)的相关文章

一步一步写算法(之二叉树广度遍历)

原文:一步一步写算法(之二叉树广度遍历) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 在二叉树的遍历当中,有一种遍历方法是不常见的,那就是广度遍历.和其他三种遍历方法不同,二叉树的广度遍历需要额外的数据结构来帮助一下?什么数据结构呢?那就是队列.因为队列具有先进先出的特点,这个特点要求我们在遍历新的一层数据之前,必须对上一次的数据全部遍历结束.暂时还没有掌握队列知识的朋友可以看一看我的这一篇博客-队列. a)下面是新添加的队列数据结构

一步一步写算法(之二叉树深度遍历)

原文:一步一步写算法(之二叉树深度遍历) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 深度遍历是软件开发中经常遇到的遍历方法.常用的遍历方法主要有下面三种:(1)前序遍历:(2)中序遍历:(3)后序遍历.按照递归的方法,这三种遍历的方法其实都不困难,前序遍历就是根-左-右,中序遍历就是左-根-右,后续遍历就是左-右-根.代码实现起来也不复杂. 1)前序遍历 void preorder_traverse(TREE_NODE* pTree

c/c++ 通用的(泛型)算法 之 只读算法,写算法,排序算法

通用的(泛型)算法 之 只读算法,写算法,排序算法 只读算法: 函数名 功能描述 accumulate 求容器里元素的和 equal 比较2个容器里的元素 写算法 函数名 功能描述 fill 用给定值,覆盖给定的范围的元素 fill_n 用给定值,覆盖给定开始位置后的,n个元素变 back_inserter 在容器末尾插入元素 copy 把容器1指定范围里的值拷贝给容器2,并返回指向容器2最后一个元素的下个元素 replace 用某个值替换掉给定范围的某个值 replace_copy 用某个值替

一步一图一代码:排序二叉树

作者:禅楼望月(http://www.cnblogs.com/yaoyinglong/) 属性: ①若它的左子树不为空,则左子树上所有节点的值均小于它的根节点的值. ②若它的右子树不为空,则右子树上所有节点的值均大于它的根节点的值. ③它的左.右子树也都是排序二叉树. 添加操作: 当根节点为空时,添加进的节点作为根节点.然后每次添加节点时,都从根节点过滤,以根节点作为当前节点,如果新节点大于当前节点,则走当前节点的右子节点分支,如果新节点小于当前节点,则走当前节点的左子节点分支.然后再用右子节点

一步一图一代码之排序二叉树

作者:禅楼望月(http://www.cnblogs.com/yaoyinglong/) 属性: ①若它的左子树不为空,则左子树上所有节点的值均小于它的根节点的值. ②若它的右子树不为空,则右子树上所有节点的值均大于它的根节点的值. ③它的左.右子树也都是排序二叉树. 添加操作: 当根节点为空时,添加进的节点作为根节点.然后每次添加节点时,都从根节点过滤,以根节点作为当前节点,如果新节点大于当前节点,则走当前节点的右子节点分支,如果新节点小于当前节点,则走当前节点的左子节点分支.然后再用右子节点

计算机程序的思维逻辑 (42) - 排序二叉树

40节介绍了HashMap,41节介绍了HashSet,它们的共同实现机制是哈希表,一个共同的限制是没有顺序,我们提到,它们都有一个能保持顺序的对应类TreeMap和TreeSet,这两个类的共同实现基础是排序二叉树,为了更好的理解TreeMap/TreeSet,本节我们先来介绍排序二叉树的一些基本概念和算法. 基本概念 先来说树的概念,现实中,树是从下往上长的,树会分叉,在计算机程序中,一般而言,与现实相反,树是从上往下长的,也会分叉,有个根节点,每个节点可以有一个或多个孩子节点,没有孩子节点

一步一步写算法(之合并排序)

原文:一步一步写算法(之合并排序) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前面一篇博客提到的快速排序是排序算法中的一种经典算法.和快速排序一样,合并排序是另外一种经常使用的排序算法.那么合并排序算法有什么不同呢?关键之处就体现在这个合并上面. 合并算法的基本步骤如下所示: 1)把0~length-1的数组分成左数组和右数组 2)对左数组和右数组进行迭代排序 3)将左数组和右数组进行合并,那么生成的整个数组就是有序的数据数组 下面

一步一步写算法(之排序二叉树)

原文:一步一步写算法(之排序二叉树) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 前面我们讲过双向链表的数据结构.每一个循环节点有两个指针,一个指向前面一个节点,一个指向后继节点,这样所有的节点像一颗颗珍珠一样被一根线穿在了一起.然而今天我们讨论的数据结构却有一点不同,它有三个节点.它是这样定义的: typedef struct _TREE_NODE { int data; struct _TREE_NODE* parent; str

一步一步写算法(之链表排序)

原文:一步一步写算法(之链表排序) [ 声明:版权所有,欢迎转载,请勿用于商业用途.  联系信箱:feixiaoxing @163.com] 相比较线性表的排序而言,链表排序的内容稍微麻烦一点.一方面,你要考虑数据插入的步骤:另外一方面你也要对指针有所顾虑.要是有一步的内容错了,那么操作系统会马上给你弹出一个exception.就链表的特殊性而言,适合于链表的排序有哪些呢? (1)插入排序    (适合) (2)冒泡排序    (适合) (3)希尔排序    (适合) (4)选择排序    (适