二叉树的实现与操作(C语言实现)

 二叉树的定义:

    上一篇的树的通用表示法太过于复杂,由此这里采用了孩子兄弟表示法来构建二叉树。

孩子兄弟表示法:

每个结点包含一个数据指针和两个结点指针

--->数据指针:指向保存于树中的数据

--->孩子结点指针:指向第一个孩子

--->兄弟结点指针:指向第一个右兄弟

二叉树是由 n( n>=0
)
个结点组成的有限集,该集合或者为空,或者是由一个根结点加上两棵分别称为左子树和右子树的、互不相交的二叉树组成。

特殊的二叉树:

定义1:满二叉树(Full
Binary Tree)

如果二叉树中所有分支结点的度数都为2,且叶子结点都在同一层次上,则称做这类二叉树为满二叉树

定义2:完全二叉树

如果一颗具有N个结点的高度为K的二叉树,它的每一个结点都与高度为K的满二叉树中的编号为1---N的结点一一对应,则称这课二叉树为完全二叉树(从上到下从左到右编号)。

注:完全二叉树的叶结点仅仅出现在最下面二层,

最下面的叶结点一定出现在左边;

倒数第二层的叶结点一定出现在右边

完全二叉树中度为1的结点只有左孩子

同样结点数的二叉树,完全二叉树的高度最小

二叉树的深层性质

性质1:

在二叉树的第i层最多有2i-1个结点。(i>=1)

性质2:

深度为K的二叉树最多有2k-1个结点(k>=0)

性质3:

对任何一颗二叉树,如果其叶结点有n0个,度为2的结点的非叶结点有n2个,则有n0=n2+1

性质4:

具有n个结点的完全二叉树的高度为[log2n]+1

性质5:

一颗有n个结点的二叉树(高度为[log2n]+1),按层次对结点进行编号(从上到下,从左到右),对任意结点i有:

如果i=1,则结点i是二叉树的根,

如果i>1,则其双亲结点为[i/2]

如果2i<=n,则结点i的左孩子为2i

如果2i>n,则结点i无左孩子,

如果2i+1<=n,则结点i的右孩子为2i+1,

如果2i+1>n,则结点i无右孩子

以下是代码:

头文件:

#ifndef _BTREE_H_
#define _BTREE_H_

#define BT_LEFT 0
#define BT_RIGHT 1

typedef void BTree;     //树
typedef unsigned long long BTPos;  //要插入结点的位置,是一个十六进制数字

typedef struct _tag_BTreeNode BTreeNode;   //定义树结点
struct _tag_BTreeNode
{
	BTreeNode* left;
	BTreeNode* right;
};

typedef void (BTree_Printf)(BTreeNode*);

BTree* BTree_Create();

void BTree_Destroy(BTree* tree);

void BTree_Clear(BTree* tree);

int BTree_Insert(BTree* tree, BTreeNode* node, BTPos pos, int count, int flag);

BTreeNode* BTree_Delete(BTree* tree, BTPos pos, int count);

BTreeNode* BTree_Get(BTree* tree, BTPos pos, int count);

BTreeNode* BTree_Root(BTree* tree);

int BTree_Height(BTree* tree);

int BTree_Count(BTree* tree);

int BTree_Degree(BTree* tree);

void BTree_Display(BTree* tree, BTree_Printf* pFunc, int gap, char div);

#endif

源文件:

#include "stdafx.h"
#include <stdio.h>
#include <malloc.h>
#include "BTree.h"

typedef struct _tag_BTree TBTree;
struct _tag_BTree    //树的头结点定义
{
	int count;
	BTreeNode* root;
};

//打印函数
static void recursive_display(BTreeNode* node, BTree_Printf* pFunc, int format, int gap, char div)
{
	int i = 0;

	if( (node != NULL) && (pFunc != NULL) )
	{
		//先打印格式符号
		for(i=0; i<format; i++)
		{
			printf("%c", div);
		}

		//打印树中具体的数据
		pFunc(node);

		printf("\n");

		//如果左 或者 右结点不为空才打印
		if( (node->left != NULL) || (node->right != NULL) )
		{
			recursive_display(node->left, pFunc, format + gap, gap, div);
			recursive_display(node->right, pFunc, format + gap, gap, div);
		}
	}
	//如果结点为空 就打印 格式符号
	else
	{
		for(i=0; i<format; i++)
		{
			printf("%c", div);
		}
		printf("\n");
	}
}

//统计树中结点的数量
static int recursive_count(BTreeNode* root)
{
	int ret = 0;

	if( root != NULL )
	{
		ret = recursive_count(root->left) + 1 + recursive_count(root->right);
	}

	return ret;
}

//计算树的高度
static int recursive_height(BTreeNode* root)
{
	int ret = 0;

	if( root != NULL )
	{
		int lh = recursive_height(root->left);
		int rh = recursive_height(root->right);

		ret = ((lh > rh) ? lh : rh) + 1;
	}

	return ret;
}

//计算树的度
static int recursive_degree(BTreeNode* root)
{
	int ret = 0;

	if( root != NULL )
	{
		if( root->left != NULL )
		{
			ret++;
		}

		if( root->right != NULL )
		{
			ret++;
		}

		if( ret == 1 )
		{
			int ld = recursive_degree(root->left);
			int rd = recursive_degree(root->right);

			if( ret < ld )
			{
				ret = ld;
			}

			if( ret < rd )
			{
				ret = rd;
			}
		}
	}

	return ret;
}

BTree* BTree_Create()
{
	TBTree* ret = (TBTree*)malloc(sizeof(TBTree));

	if( ret != NULL )
	{
		ret->count = 0;
		ret->root = NULL;
	}

	return ret;
}

void BTree_Destroy(BTree* tree)
{
	free(tree);
}

void BTree_Clear(BTree* tree)
{
	TBTree* btree = (TBTree*)tree;

	if( btree != NULL )
	{
		btree->count = 0;
		btree->root = NULL;
	}
}

//tree  目标树  node 要插入结点   pos 要插入位置  count 移动步数  flag  插入位置是左还是右
int BTree_Insert(BTree* tree, BTreeNode* node, BTPos pos, int count, int flag)
{
	TBTree* btree = (TBTree*)tree;
	int ret = (btree != NULL) && (node != NULL) && ((flag == BT_LEFT) || (flag == BT_RIGHT));
	int bit = 0;

	if( ret )
	{
		BTreeNode* parent = NULL;
		BTreeNode* current = btree->root;

		node->left = NULL;
		node->right = NULL;

		while( (count > 0) && (current != NULL) )
		{
			//位置最低位与1进行按位与运算,得知是往左走还是往右走
			bit = pos & 1;
			//表示位置的十六进制向右移动一位
			pos = pos >> 1;

			//parent用来挂要插入的结点
			parent = current;

			if( bit == BT_LEFT )
			{
				current = current->left;
			}
			else if( bit == BT_RIGHT )
			{
				current = current->right;
			}

			count--;
		}

		//插入的结点挂上中间被砍断的剩下的结点
		if( flag == BT_LEFT )
		{
			node->left = current;
		}
		else if( flag == BT_RIGHT )
		{
			node->right = current;
		}

		//将要插入的结点挂上
		if( parent != NULL )
		{
			if( bit == BT_LEFT )
			{
				parent->left = node;
			}
			else if( bit == BT_RIGHT )
			{
				parent->right = node;
			}
		}
		else
		{
			btree->root = node;
		}

		btree->count++;
	}

	return ret;
}

//删除与插入基本类似,只不过将要删除的结点的父结点的left或者right指针以及所有的子节点置为NULL而已
BTreeNode* BTree_Delete(BTree* tree, BTPos pos, int count)
{
	TBTree* btree = (TBTree*)tree;
	BTreeNode* ret = NULL;
	int bit = 0;

	if( btree != NULL )
	{
		BTreeNode* parent = NULL;
		BTreeNode* current = btree->root;

		while( (count > 0) && (current != NULL) )
		{
			bit = pos & 1;
			pos = pos >> 1;

			parent = current;

			if( bit == BT_LEFT )
			{
				current = current->left;
			}
			else if( bit == BT_RIGHT )
			{
				current = current->right;
			}

			count--;
		}

		if( parent != NULL )
		{
			if( bit == BT_LEFT )
			{
				parent->left = NULL;
			}
			else if( bit == BT_RIGHT )
			{
				parent->right = NULL;
			}
		}
		else
		{
			btree->root = NULL;
		}

		ret = current;

		btree->count = btree->count - recursive_count(ret);
	}

	return ret;
}

BTreeNode* BTree_Get(BTree* tree, BTPos pos, int count)
{
	TBTree* btree = (TBTree*)tree;
	BTreeNode* ret = NULL;
	int bit = 0;

	if( btree != NULL )
	{
		BTreeNode* current = btree->root;

		while( (count > 0) && (current != NULL) )
		{
			bit = pos & 1;
			pos = pos >> 1;

			if( bit == BT_LEFT )
			{
				current = current->left;
			}
			else if( bit == BT_RIGHT )
			{
				current = current->right;
			}

			count--;
		}

		ret = current;
	}

	return ret;
}

BTreeNode* BTree_Root(BTree* tree)
{
	TBTree* btree = (TBTree*)tree;
	BTreeNode* ret = NULL;

	if( btree != NULL )
	{
		ret = btree->root;
	}

	return ret;
}

int BTree_Height(BTree* tree)
{
	TBTree* btree = (TBTree*)tree;
	int ret = 0;

	if( btree != NULL )
	{
		ret = recursive_height(btree->root);
	}

	return ret;
}

int BTree_Count(BTree* tree)
{
	TBTree* btree = (TBTree*)tree;
	int ret = 0;

	if( btree != NULL )
	{
		ret = btree->count;
	}

	return ret;
}

int BTree_Degree(BTree* tree)
{
	TBTree* btree = (TBTree*)tree;
	int ret = 0;

	if( btree != NULL )
	{
		ret = recursive_degree(btree->root);
	}

	return ret;
}

void BTree_Display(BTree* tree, BTree_Printf* pFunc, int gap, char div)
{
	TBTree* btree = (TBTree*)tree;

	if( btree != NULL )
	{
		recursive_display(btree->root, pFunc, 0, gap, div);
	}
}

主函数:

// 二叉树.cpp : 定义控制台应用程序的入口点。
//

#include "stdafx.h"
#include "BTree.h"
#include <iostream>

struct Node    //数据结点
{
	BTreeNode header;
	char v;
};

void printf_data(BTreeNode* node)   //打印树
{
	if( node != NULL )
	{
		printf("%c", ((struct Node*)node)->v);
	}
}

int _tmain(int argc, _TCHAR* argv[])
{

	BTree* tree = BTree_Create();

	struct Node n1 = {{NULL, NULL}, 'A'};
	struct Node n2 = {{NULL, NULL}, 'B'};
	struct Node n3 = {{NULL, NULL}, 'C'};
	struct Node n4 = {{NULL, NULL}, 'D'};
	struct Node n5 = {{NULL, NULL}, 'E'};
	struct Node n6 = {{NULL, NULL}, 'F'};

	BTree_Insert(tree, (BTreeNode*)&n1, 0, 0, 0);
	BTree_Insert(tree, (BTreeNode*)&n2, 0x00, 1, 0);
	BTree_Insert(tree, (BTreeNode*)&n3, 0x01, 1, 0);
	BTree_Insert(tree, (BTreeNode*)&n4, 0x00, 2, 0);
	BTree_Insert(tree, (BTreeNode*)&n5, 0x02, 2, 0);
	BTree_Insert(tree, (BTreeNode*)&n6, 0x02, 3, 0);

	printf("Height: %d\n", BTree_Height(tree));
	printf("Degree: %d\n", BTree_Degree(tree));
	printf("Count: %d\n", BTree_Count(tree));
	printf("Position At (0x02, 2): %c\n", ((struct Node*)BTree_Get(tree, 0x02, 2))->v);
	printf("Full Tree: \n");

	BTree_Display(tree, printf_data, 4, '-');

	//以下是删除结点位置在0x00的结点后,树的整体状态

	BTree_Delete(tree, 0x00, 1);

	printf("After Delete B: \n");
	printf("Height: %d\n", BTree_Height(tree));
	printf("Degree: %d\n", BTree_Degree(tree));
	printf("Count: %d\n", BTree_Count(tree));
	printf("Full Tree: \n");

	BTree_Display(tree, printf_data, 4, '-');

	//以下是清空树后,树的整体状态

	BTree_Clear(tree);

	printf("After Clear: \n");
	printf("Height: %d\n", BTree_Height(tree));
	printf("Degree: %d\n", BTree_Degree(tree));
	printf("Count: %d\n", BTree_Count(tree));

	BTree_Display(tree, printf_data, 4, '-');

	BTree_Destroy(tree);

	system("pause");
	return 0;
}

运行结构:

Height: 4
Degree: 2
Count: 6
Position At (0x02, 2): E
Full Tree:
A
----B
--------D
--------E
------------F
------------
----C
After Delete B:
Height: 2
Degree: 1
Count: 2
Full Tree:
A
----
----C
After Clear:
Height: 0
Degree: 0
Count: 0

请按任意键继续. . .

如有错误,望不吝指出呀。

二叉树的实现与操作(C语言实现)

时间: 2024-10-09 23:05:33

二叉树的实现与操作(C语言实现)的相关文章

树的实现与操作(C语言实现)

首先来简单说下一些关于的基本概念. 树是一种非线性的数据结构 1,树是由 n(n>=0)个结点组成的有限集合 如果n = 0 ,称为空树 如果n > 0,则: 有一个特定的称之为根(root)的结点,它只有直接后继,但没有直接前驱 除了根以外的其他结点划分为:m(m>=0)个互不相交的有限集合,T0,T1,T2-Tn-1,每个集合又是一棵树,并且称之为根的子树 2,树中的概念: 树的结点包括一个数据及若干指向子树的分支 结点拥有的子树树称为结点的度 度为0的结点称为叶结点 度不为0的结点

栈的实现与操作(C语言实现)

栈的定义  1, 栈是一种特殊的线性表  2,栈仅能在线性表的一端进行操作  3,栈顶(Top): 同意操作的一端 同意操作的一端  4,栈底(Bottom): ,不同意操作的一端 不同意操作的一端 这里我做出了 栈的顺序实现 和 链式实现.分别例如以下: =========================================华丽丽的切割线========================================================== 栈的顺序实现: 首先

静态链表的实现与操作(C语言实现)

我们知道要实现单链表,必须要有指针,那么像Java这样没有指针的的语言就略显蛋疼了. 没关系,我们有静态链表,其本质就是用采用数组的方式实现单链表的功能. 头文件: #ifndef _StaticLinkList_H_ #define _StaticLinkList_H_ typedef void StaticLinkList; typedef void StaticLinkListNode; StaticLinkList * StaticLinkList_Create(int capacity

给定一个二进制数,要求循环移位,在原二进制数中操作(C语言)

int b = 0, c = 0;// b 输入的0~255之间的数 c 移动位数 printf("请输入一个整数和移动位数\n"); scanf("%d%d", &b, &c); unsigned char a = b; unsigned char left = 0;//存储左移之后的结果     unsigned char right = 0;//存储右移之后的结果     //循环移位 right = a >> c; left =

二叉树的8种操作

1.为什么会有树?因为当有大量的输入数据时,链表的线性访问时间就显得略长了.而树结构,其大部分操作的运行时间平均为O(logN). 2.树的实现并不难,几行代码就搞定了. struct TreeNode { Object element; TreeNode *firstChild; TreeNode *nextSibling; } 3.遍历形式: // 中序遍历二叉树 void inorder(tree_pointer ptr) { if(ptr) { inorder(ptr->left_chi

双向链表的实现与操作(C语言实现)

双向链表也叫双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱.所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点.一般我们都构造双向循环链表. 单链表的局限 1,单链表的结点都只有一个指向下一个结点的指针 2,单链表的数据元素无法直接访问其前驱元素 3,逆序访问单链表中的元素是极其耗时的操作 双向链表的操作 双向链表的新操作 1,获取当前游标指向的数据元素 2,将游标重置指向链表中的第一个数据元素 3,将游标移动指向到链表中的下一个数据

neo4j初次使用学习简单操作-cypher语言使用

Neo4j 使用cypher语言进行操作 Cypher语言是在学习Neo4j时用到数据库操作语言(DML),涵盖对图数据的增删改查  neo4j数据库简单除暴理解的概念: Neo4j中不存在表的概念,只有两类:节点(Node)和关联(Relation),可以简单理解为图里面的点和边.在数据查询中,节点一般用小括号(),关联用中括号[].当然也隐含路径的概念,是用节点和关联表示的,如:(a)-[r]->(b),表示一条从节点a经关联r到节点b的路径.  备份Neo4j的数据: 1)停掉数据库. 2

循环链表的实现与操作(C语言实现)

循环链表是另一种形式的链式存贮结构.它的特点是表中最后一个结点的指针域指向头结点,整个链表形成一个环. 循环链表的操作 1,循环链表的新操作 2, 获取当前游标指向的数据元素 3, 将游标重置指向链表中的第一个数据元素 4,将游标移动指向到链表中的下一个数据元素 5,直接指定删除链表中的某个数据元素 CircleListNode* CircleList_DeleteNode(CircleList* list, CircleListNode* node); CircleListNode*

数据结构-二叉树的遍历(类C语言描写叙述)

遍历概念 所谓遍历(Traversal)是指沿着某条搜索路线.依次对树中每一个结点均做一次且仅做一次訪问.訪问结点所做的操作依赖于详细的应用问题. 遍历是二叉树上最重要的运算之中的一个,是二叉树上进行其他运算之基础. 遍历方案 1.遍历方案 从二叉树的递归定义可知,一棵非空的二叉树由根结点及左.右子树这三个基本部分组成.因此.在任一给定结点上,能够按某种次序运行三个操作: (1)訪问结点本身(N), (2)遍历该结点的左子树(L), (3)遍历该结点的右子树(R). 以上三种操作有六种运行次序: