看数据结构写代码(31)树的二叉链表的实现
来源:互联网 发布:如何用阿里云os系统 编辑:程序博客网 时间:2024/05/29 19:08
首先向大家推荐一个 很棒的 介绍 树,二叉树,森林之间转换的博客:点击打开链接
源码网盘地址:点击打开链接
树的二叉链表 和 二叉树的 二叉链表 在存储结构上 是一致的,但是 具体 含义 不同; 树节点的 两个指针 指向 第一个孩子节点 和 右兄弟 节点,而 二叉链表指向 左,右子树。这就表示了 他们的操作 既有相同的地方,又有不同的地方。
例如 树的 先序遍历,销毁子树,求树的长度 和 二叉树的 操作 是一样的。
void treeClear(Tree * tree){if (*tree != NULL){treeClear(&((*tree)->firstChild));treeClear(&((*tree)->nextSibling));free(*tree);*tree = NULL;}}void treeDestory(Tree * tree){treeClear(tree);}//先跟节点 遍历...在孩子void preOrderTraverse(Tree tree){if (tree != NULL){printf("%c\t",tree->data);preOrderTraverse(tree->firstChild);preOrderTraverse(tree->nextSibling);}}
//树求 长度 和 二叉树 求长度 一样. int treeLen(Tree tree){ if (tree != NULL) { return treeLen(tree->firstChild) + treeLen(tree->nextSibling) + 1; } return 0; }
树的后序遍历(没有右子树,所以没有中序遍历)和 二叉树的 中序遍历时一样的。
void postOrderTraverse(Tree tree){if (tree != NULL){/*postOrderTraverse(tree->firstChild);postOrderTraverse(tree->nextSibling);printf("%c\t",tree->data);*/postOrderTraverse(tree->firstChild);printf("%c\t",tree->data);postOrderTraverse(tree->nextSibling);}}
树的层序遍历,和二叉树 在形式上 是类似的,树是 将所有孩子节点 入队列,而二叉树 是将 左右子树入队列
//层序遍历 (根二叉树的遍历 略有不同)void levelOrderTraverse(Tree tree){if (tree != NULL){LinkQueue queue;queueInit(&queue);enqueue(&queue,tree);while (!queueEmpty(queue)){Tree father;dequeue(&queue,&father);printf("%c\t",father->data);Tree child = father->firstChild;//等于第一个孩子////将所有孩子节点 入队(相当于 二叉树的 将 左右 子树 入队)while (child != NULL){enqueue(&queue,child);child = child->nextSibling;}}queueDestory(&queue);}}在求树的深度 得注意:二叉树 是求 左右子树 取 最大值 + 1,而 树的 左子树代表 孩子节点, 右子树 代表的是 兄弟,所以 右子树 不 + 1.
//求树的深度 int treeDepth(Tree tree){if (tree != NULL){int leftDepth = treeDepth(tree->firstChild) + 1;int rightDepth = treeDepth(tree->nextSibling);//注意 从右子树 返回的 没有 加1,因为右子树返回的是 兄弟节点的 深度return leftDepth > rightDepth ? leftDepth : rightDepth;}return 0;}求树的叶子节点 得注意,二叉树 是 遇到 左右子树为空 就 返回1,若是 树在 遇到 firstChild为NULL 就返回,那样 就没有 判断兄弟节点 上的 叶子 节点。
int treeLeafCount(Tree tree){if (tree != NULL){if (tree->firstChild == NULL)//第一个孩子都不存在,肯定是叶子节点..{printf("%c\t",tree->data);//return 1;//还没有访问 树的 兄弟节点呢。。。return 1 + treeLeafCount(tree->nextSibling);}return treeLeafCount(tree->firstChild) + treeLeafCount(tree->nextSibling);}return 0;}
求树的宽度,求节点的层数,求双亲,求所有孩子节点,求所有兄弟节点 其实 都是 层序遍历,根二叉树的 不同点,上面已经说过。
//求树的宽度(每一层节点数比较之后的最大值)//层序法int treeWidth(Tree tree){int maxWidth = 0;//层的最大节点数if (tree != NULL){maxWidth = 0;//第一层只有根节点..int curWidth = 1;//当前层的节点数int nextWidth = 0;//下一层的节点数..LinkQueue queue;queueInit(&queue);enqueue(&queue,tree);while (!queueEmpty(queue)){for (; curWidth > 0; curWidth--){Tree father;dequeue(&queue,&father);Tree child = father->firstChild;//等于第一个孩子////将所有孩子节点 入队(相当于 二叉树的 将 左右 子树 入队)while (child != NULL){enqueue(&queue,child);child = child->nextSibling;nextWidth++;//计算出 每一层的宽度}}curWidth = nextWidth;maxWidth = maxWidth < nextWidth ? nextWidth : maxWidth;nextWidth = 0;}queueDestory(&queue);}return maxWidth;}//求节点的层数//跟 求 树的 宽度 基本上一致int treeLevel(Tree tree,TDataType data){int level = 0;if (tree != NULL){int curWidth =1;int nextWidth = 0;LinkQueue queue;queueInit(&queue);enqueue(&queue,tree);while (!queueEmpty(queue)){//每循环一次 加 一层level++;for (; curWidth > 0; curWidth--){Tree father;dequeue(&queue,&father);if (father->data == data){queueDestory(&queue);return level;}Tree child = father->firstChild;//等于第一个孩子////将所有孩子节点 入队(相当于 二叉树的 将 左右 子树 入队)while (child != NULL){enqueue(&queue,child);child = child->nextSibling;nextWidth++;//计算出 每一层的宽度}}curWidth = nextWidth;nextWidth = 0;}queueDestory(&queue);}return level;}//打印父节点的值//跟二叉树 不一致,有误区(不能用 tree->firstChild->data == childData 作为判断条件)//思路 : 层序遍历.Tree treeGetParent(Tree tree,TDataType childData){if (tree != NULL){LinkQueue queue;queueInit(&queue);enqueue(&queue,tree);while (!queueEmpty(queue)){Tree father;dequeue(&queue,&father);Tree child = father->firstChild;//等于第一个孩子////将所有孩子节点 入队(相当于 二叉树的 将 左右 子树 入队)while (child != NULL){if (child->data == childData){queueDestory(&queue);return father;}enqueue(&queue,child);child = child->nextSibling;}}queueDestory(&queue);}return NULL;}//打印所有的孩子节点.void treeGetAllChild(Tree fatherTree){if (fatherTree != NULL){printf("%c节点的孩子有:",fatherTree->data);Tree child = fatherTree->firstChild;for (; child != NULL; child = child->nextSibling){printf("%c\t",child->data);}printf("\n");}}//打印出所有的兄弟节点.void treeGetAllBrother(Tree tree,TDataType data){Tree fatherTree = treeGetParent(tree,data);//找到父节点printf("%c节点的兄弟有:",data);if (fatherTree != NULL){Tree child = fatherTree->firstChild;for (; child != NULL; child = child->nextSibling){if (child->data != data){printf("%c\t",child->data);}}printf("\n");}}在求 节点的祖先 和 最近 祖先问题上,原本准备操作 一把,可是 上网百度的时候 看到 一篇 《淘宝面试题,在一亿个节点的树中,查找两个节点的最近祖先》的面试题,网上 有人 给出了 答案,在 树的 二叉 链表 和 三叉链表 数据结构中 的算法 完全不同。可知 三叉链表 多了 一个 父亲 节点 带来 很大的方便 和 效率。
看来 相同问题,不同数据结构,算法步骤不同,算法的效率 和存储空间也不同。选择 合适的 数据结构很重要。
所以 就不准备 写 这两个函数的 具体实现了。
下面 上完整代码:
// BinaryLinkTree.cpp : 定义控制台应用程序的入口点。//#include "stdafx.h"#include "queue.h"#include "stack.h"#include <cstring>typedef char TDataType;//树的数据域的类型//树的二叉链表表示法(孩子兄弟)typedef struct TreeNode{TDataType data;TreeNode * firstChild;//指向第一个孩子TreeNode * nextSibling;//指向 下一个兄弟..} * Tree;Tree makeNode(TDataType data){Tree tree = (Tree)malloc(sizeof(TreeNode));tree->data = data;tree->firstChild = NULL;tree->nextSibling = NULL;return tree;}//初始化成空表void treeInit(Tree * tree){*tree = NULL;}E_State treeCreate(Tree * tree){TDataType data = ' ';printf("------------层序创建树(输入根节点数据,#代表空树)-------------\n");scanf("%c",&data);if (data != '#'){*tree = makeNode(data);if (*tree == NULL){return E_State_Error;}LinkQueue queue;queueInit(&queue);enqueue(&queue,*tree);while (!queueEmpty(queue)){qElementType father;dequeue(&queue,&father);printf("--------请输入%c节点的 所有 孩子节点(输入exit 表示创建完毕)-------\n",father->data);char childArray[100];scanf("%s",childArray);if (strcmp(childArray,"exit") == 0){break;}char * p = childArray;Tree preTree = NULL;while (*p != '\0'){Tree childTree = makeNode(*p);if (childTree == NULL){queueDestory(&queue);//记得 要 销毁 队列..return E_State_Error;}if (p == childArray)//第一个孩子节点{father->firstChild = childTree;}else//设置上一个节点的 兄弟..{preTree->nextSibling = childTree;}//将节点 入队列..preTree = childTree;enqueue(&queue,childTree);p ++;}}queueDestory(&queue);}else//空树{treeInit(tree);}return E_State_Ok;}//释放空间,并设置成空树...//树的二叉链表形式,存储结构 等同于 二叉树的 二叉链表..//所以 先释放 第一个孩子节点(左子树),再释放兄弟节点(右子树) 最后 释放 根节点..void treeClear(Tree * tree){if (*tree != NULL){treeClear(&((*tree)->firstChild));treeClear(&((*tree)->nextSibling));free(*tree);*tree = NULL;}}void treeDestory(Tree * tree){treeClear(tree);}//先跟节点 遍历...在孩子void preOrderTraverse(Tree tree){if (tree != NULL){printf("%c\t",tree->data);preOrderTraverse(tree->firstChild);preOrderTraverse(tree->nextSibling);}}//由于 树的根节点 无 兄弟节点,所以 树根的 右子树 必为空//所以树 无 后序,只有中序//用二叉树的 中序 表示.void postOrderTraverse(Tree tree){if (tree != NULL){/*postOrderTraverse(tree->firstChild);postOrderTraverse(tree->nextSibling);printf("%c\t",tree->data);*/postOrderTraverse(tree->firstChild);printf("%c\t",tree->data);postOrderTraverse(tree->nextSibling);}}//层序遍历 (根二叉树的遍历 略有不同)void levelOrderTraverse(Tree tree){if (tree != NULL){LinkQueue queue;queueInit(&queue);enqueue(&queue,tree);while (!queueEmpty(queue)){Tree father;dequeue(&queue,&father);printf("%c\t",father->data);Tree child = father->firstChild;//等于第一个孩子////将所有孩子节点 入队(相当于 二叉树的 将 左右 子树 入队)while (child != NULL){enqueue(&queue,child);child = child->nextSibling;}}queueDestory(&queue);}}bool treeIsEmpty(Tree tree){return tree == NULL ? true : false;}//树求 长度 和 二叉树 求长度 一样.int treeLen(Tree tree){if (tree != NULL){return treeLen(tree->firstChild) + treeLen(tree->nextSibling) + 1;}return 0;}//求树的深度 int treeDepth(Tree tree){if (tree != NULL){int leftDepth = treeDepth(tree->firstChild) + 1;int rightDepth = treeDepth(tree->nextSibling);//注意 从右子树 返回的 没有 加1,因为右子树返回的是 兄弟节点的 深度return leftDepth > rightDepth ? leftDepth : rightDepth;}return 0;}//求树的叶子树,并打印这些叶子节点.//只要 firstChild为NULl 就是 叶子节点 (二叉树 是 左右 子树 都为NULL。)//先序遍历int treeLeafCount(Tree tree){if (tree != NULL){if (tree->firstChild == NULL)//第一个孩子都不存在,肯定是叶子节点..{printf("%c\t",tree->data);//return 1;//还没有访问 树的 兄弟节点呢。。。return 1 + treeLeafCount(tree->nextSibling);}return treeLeafCount(tree->firstChild) + treeLeafCount(tree->nextSibling);}return 0;}//求树的宽度(每一层节点数比较之后的最大值)//层序法int treeWidth(Tree tree){int maxWidth = 0;//层的最大节点数if (tree != NULL){maxWidth = 0;//第一层只有根节点..int curWidth = 1;//当前层的节点数int nextWidth = 0;//下一层的节点数..LinkQueue queue;queueInit(&queue);enqueue(&queue,tree);while (!queueEmpty(queue)){for (; curWidth > 0; curWidth--){Tree father;dequeue(&queue,&father);Tree child = father->firstChild;//等于第一个孩子////将所有孩子节点 入队(相当于 二叉树的 将 左右 子树 入队)while (child != NULL){enqueue(&queue,child);child = child->nextSibling;nextWidth++;//计算出 每一层的宽度}}curWidth = nextWidth;maxWidth = maxWidth < nextWidth ? nextWidth : maxWidth;nextWidth = 0;}queueDestory(&queue);}return maxWidth;}//求节点的层数//跟 求 树的 宽度 基本上一致int treeLevel(Tree tree,TDataType data){int level = 0;if (tree != NULL){int curWidth =1;int nextWidth = 0;LinkQueue queue;queueInit(&queue);enqueue(&queue,tree);while (!queueEmpty(queue)){//每循环一次 加 一层level++;for (; curWidth > 0; curWidth--){Tree father;dequeue(&queue,&father);if (father->data == data){queueDestory(&queue);return level;}Tree child = father->firstChild;//等于第一个孩子////将所有孩子节点 入队(相当于 二叉树的 将 左右 子树 入队)while (child != NULL){enqueue(&queue,child);child = child->nextSibling;nextWidth++;//计算出 每一层的宽度}}curWidth = nextWidth;nextWidth = 0;}queueDestory(&queue);}return level;}//打印父节点的值//跟二叉树 不一致,有误区(不能用 tree->firstChild->data == childData 作为判断条件)//思路 : 层序遍历.Tree treeGetParent(Tree tree,TDataType childData){if (tree != NULL){LinkQueue queue;queueInit(&queue);enqueue(&queue,tree);while (!queueEmpty(queue)){Tree father;dequeue(&queue,&father);Tree child = father->firstChild;//等于第一个孩子////将所有孩子节点 入队(相当于 二叉树的 将 左右 子树 入队)while (child != NULL){if (child->data == childData){queueDestory(&queue);return father;}enqueue(&queue,child);child = child->nextSibling;}}queueDestory(&queue);}return NULL;}//打印所有的孩子节点.void treeGetAllChild(Tree fatherTree){if (fatherTree != NULL){printf("%c节点的孩子有:",fatherTree->data);Tree child = fatherTree->firstChild;for (; child != NULL; child = child->nextSibling){printf("%c\t",child->data);}printf("\n");}}//打印出所有的兄弟节点.void treeGetAllBrother(Tree tree,TDataType data){Tree fatherTree = treeGetParent(tree,data);//找到父节点printf("%c节点的兄弟有:",data);if (fatherTree != NULL){Tree child = fatherTree->firstChild;for (; child != NULL; child = child->nextSibling){if (child->data != data){printf("%c\t",child->data);}}printf("\n");}}//求节点的祖先void treeGetAllParent(Tree tree,TDataType data){}//求节点的最近公共祖先TDataType treeFindCommonAncestor(Tree tree,TDataType data1,TDataType data2){return ' ';}int _tmain(int argc, _TCHAR* argv[]){Tree tree;treeCreate(&tree);printf("------------先序遍历------------\n");preOrderTraverse(tree);printf("------------后(中)序遍历------------\n");postOrderTraverse(tree);printf("------------层序遍历------------\n");levelOrderTraverse(tree);printf("\n树的叶子节点是:");int leafCount = treeLeafCount(tree);printf(",叶子节点数为:%d\n",leafCount);int len = treeLen(tree);char * isEmpty = treeIsEmpty(tree) ? "是" : "不是";int depath = treeDepth(tree);int width = treeWidth(tree);printf("树是否为空:%s,长度是:%d,深度是:%d,宽度是:%d\n",isEmpty,len,depath,width);int level = treeLevel(tree,'e');printf("节点e的所在层数是:%d\n",level);Tree father = treeGetParent(tree,'h');printf("h节点的父节点是:%c\n",father->data);treeGetAllChild(father);treeGetAllBrother(tree,father->data);treeDestory(&tree);return 0;}运行截图:
1 0
- 看数据结构写代码(31)树的二叉链表的实现
- 看数据结构写代码(23) 二叉链表的实现
- 看数据结构写代码(28) 线索二叉链表的实现
- 看数据结构写代码(27) 三叉链表的实现
- 看数据结构写代码(9)链栈的实现
- 看数据结构写代码(3)顺序表的 实现
- 看数据结构写代码(26) 求二叉链表 任意 两个节点的 最近祖先
- 看数据结构写代码(37) 图的十字链表的表示与实现
- 看数据结构写代码(6)双向链表的实现
- 看数据结构写代码(8)顺序栈的实现
- 看数据结构写代码(19) 数组的实现
- 看数据结构写代码(30) 树的双亲孩子表示法的实现
- 看数据结构写代码(22) 二叉树的顺序存储方式
- 看数据结构写代码(24) 二叉链表的递归遍历 和 非递归遍历 算法 总结
- 看数据结构写代码(57) AVL树的删除
- 初学数据结构自己写的二叉树,方便以后看
- 看数据结构写代码(60 ) 键树的多重链表表示(Trie树)
- 看数据结构写代码(52) 广义表的扩展线性链表存储表示
- vmware tools+ubuntu+androidOS编译环境配置全过程
- A class file not written.
- 不错的博文 适配
- 算法——先进先出队列
- 杭电 HDU 1048 The Hardest Problem Ever
- 看数据结构写代码(31)树的二叉链表的实现
- 题目1066 字符串排序 九度Online Judge
- UVa #11082 Matrix Decompressing (例题11-8)
- Android数据存储方式之:数据库操作
- web.xml学习笔记
- ViewDragHelper.CallBack中每个方法的用法
- 校内互测第二周(East!XVI~East!XX)总结(被虐启示录
- iframe 高度显示不正确解决方法 IE
- app应用之间的跳转代码