看数据结构写代码(31)树的二叉链表的实现

首先向大家推荐一个 很棒的 介绍 树,二叉树,森林之间转换的博客:点击打开链接

源码网盘地址:点击打开链接

树的二叉链表 和 二叉树的 二叉链表 在存储结构上 是一致的,但是 具体 含义 不同; 树节点的 两个指针 指向 第一个孩子节点 和 右兄弟 节点,而 二叉链表指向 左,右子树。这就表示了 他们的操作 既有相同的地方,又有不同的地方。

例如 树的 先序遍历,销毁子树,求树的长度 和 二叉树的 操作 是一样的。

void treeClear(Tree * tree){if (*tree != NULL){treeClear(&((*tree)->firstChild));treeClear(&((*tree)->firstChild));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){<span style="white-space:pre"></span>if (tree != NULL)<span style="white-space:pre"></span>{<span style="white-space:pre"></span>return treeLen(tree->firstChild) + treeLen(tree->nextSibling) + 1;<span style="white-space:pre"></span>}<span style="white-space:pre"></span>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");}}在求 节点的祖先 和 最近 祖先问题上,原本准备操作 一把,可是 上网百度的时候 看到 一篇 《淘宝面试题,在一亿个节点的树中,查找两个节点的最近祖先》的面试题,网上 有人 给出了 答案,在 树的 二叉 链表 和 三叉链表 数据结构中 的算法 完全不同。可知 三叉链表 多了 一个 父亲 节点 带来 很大的方便 和 效率。

看来 相同问题,不同数据结构,算法步骤不同,算法的效率 和存储空间也不同。选择 合适的 数据结构很重要。

所以 就不准备 写 这两个函数的 具体实现了。

人,都有不能称心如意的时候,都有愿望落空的窘迫,

看数据结构写代码(31)树的二叉链表的实现

相关文章:

你感兴趣的文章:

标签云: