数据结构的实践心得(二叉树的抽象数据结构和各种遍历的递归及非递归实现,以及哈夫曼算法应用:binaryTree)

Posted 咕咚的小宇宙

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了数据结构的实践心得(二叉树的抽象数据结构和各种遍历的递归及非递归实现,以及哈夫曼算法应用:binaryTree)相关的知识,希望对你有一定的参考价值。

头文件(binaryTree.h):

#pragma once


#define BinaryTreeOrderBUFFER 128


typedef double binaryElemType;

typedef struct

{

int key; // 二叉树节点关键字(优先数)

binaryElemType *data; // 数据内容

int dataSize; // 数据内容的空间大小

struct binaryNode *parent; // 父节点

struct binaryNode *left; // 左节点

struct binaryNode *right; // 右节点

int length; // 二叉树的节点数量(包括所有子节点)

int isRight; // 如果是子节点,则是否为右节点(右:1;左:0)

}binaryNode;


// 创建二叉树节点

binaryNode* createBinaryNode(int dataSize);

// 设置二叉树节点的数据内容

void setBinaryNodeData(binaryNode *T, binaryElemType *e);

// 是否为叶子节点返回1,否则返回0

int isLeafBinaryNode(binaryNode *T);

// 二叉树的节点数量

int lengthBinaryList(binaryNode *T);


// 二叉树的节点数量(递归)

int lengthBinaryListRecursion(binaryNode *T);

// 取得二叉树节点的层级

int levelBinaryNode(binaryNode *T);

// 取得子节点的相对层级

int levelBinaryChildNode(binaryNode *T, binaryNode *child);

// 取得二叉树节点的根节点

binaryNode* getBinaryRoot(binaryNode *T);


// 插入二叉树的子节点(右:1;左:0)

binaryNode* insertBinaryNode(binaryNode *T, int isRight, int key);

// 添加二叉树的子节点(右:1;左:0)

binaryNode* addBinaryNode(binaryNode *T, int isRight, binaryNode *child);

// 移除二叉树的子节点

int removeBinaryNode(binaryNode *T, binaryNode *child);

// 清空二叉树列表(递归)

void clearBinaryList(binaryNode *T);


// 层次遍历(输出节点的排序数组)

int levelOrder(binaryNode *T, binaryNode **orderList);

// 前序遍历(递归)

int preOrderRecursion(binaryNode *T, binaryNode **orderList);

// 前序遍历(输出数据的排序数组)

int preOrder(binaryNode *T, binaryNode **orderList);

// 中序遍历(递归)

int middleOrderRecursion(binaryNode *T, binaryNode **orderList);

// 中序遍历(输出数据的排序数组)

int middleOrder(binaryNode *T, binaryNode **orderList);

// 后序遍历(递归)

int postOrderRecursion(binaryNode *T, binaryNode **orderList);

// 后序遍历(输出数据的排序数组)

int postOrder(binaryNode *T, binaryNode **orderList);


// 生成最优二叉树(哈夫曼算法),返回二叉树根节点,参数传出叶子节点关系

binaryNode* bestBinaryTree(binaryNode *dataListOutleaf, int dataLen);

// 取得哈夫曼编码(叶子节点列表),注意在外部释放每个hfCode的内存空间

char** getHuffmanCodeByLeaf(binaryNode *leafList, int leafLen, char **hfCodeList);

// 取得哈夫曼编码,注意在外部释放每个hfCode的内存空间

char** getHuffmanCode(binaryNode *dataList, int dataLen, char **hfCodeList);


程序文件(binaryTree.c):

#include <stdlib.h>

#include "mystring.h"

#include "linkQueue.h"

#include "linkStack.h"

#include "binaryTree.h"


// 创建二叉树节点

binaryNode* createBinaryNode(int dataSize)

{

// 首先申请自己的内存空间

binaryNode *bn = (binaryNode *)malloc(sizeof(binaryNode));

if (!bn) return NULL;


if (dataSize > 0)

{

bn->data = (binaryElemType *)malloc(sizeof(binaryElemType) * dataSize);

if (!bn->data)

{

// 清空二叉树列表(递归)

clearBinaryList(bn);

return NULL;

}

bn->dataSize = dataSize;

}

else

{

bn->data = NULL;

bn->dataSize = 0;

}


bn->key = 0;

bn->parent = NULL;

bn->left = NULL;

bn->right = NULL;

bn->length = 1;

bn->isRight = 0;


return bn;

}


// 设置二叉树节点的数据内容

void setBinaryNodeData(binaryNode *T, binaryElemType *data)

{

if ((!T) || (!data)) return;


// 判断数据内容是否有效

if (T->data)

{

// 是否包含数据内容

int i;

// 设置数据内容

for (i = 0; i < T->dataSize; i++)

{

T->data[i] = data[i];

}

}

}


// 是否为叶子节点返回1,否则返回0

int isLeafBinaryNode(binaryNode *T)

{

if (!T) return -1;


return ((!T->left) && (!T->right));

}


// 二叉树的节点数量

int lengthBinaryList(binaryNode *T)

{

if (!T) return 0;


// 判断节点数量是否有效

if (T->length > 0)

{

return T->length;

}

else

{

// 二叉树的节点数量(递归)

return lengthBinaryListRecursion(T);

}

}


// 二叉树的节点数量(递归)

int lengthBinaryListRecursion(binaryNode *T)

{

if (!T) return 0;

// 二叉树的节点数量

int len = 1;


// 递归记录左子树数量

len += lengthBinaryList(T->left);

// 递归记录右子树数量

len += lengthBinaryList(T->right);


// 更新节点数量

T->length = len;

return len;

}


// 取得二叉树节点的层级

int levelBinaryNode(binaryNode *T)

{

if (!T) return -1;

// 从 0 开始

int level = 0;


binaryNode *bn = T;

// 判断父级节点

while (bn->parent)

{

level++;

// 递归父级节点

bn = bn->parent;

}

return level;

}


// 取得子节点的相对层级

int levelBinaryChildNode(binaryNode *T, binaryNode *child)

{

if ((!T) || (!child)) return -1;

// 从 0 开始

int level = 0;


binaryNode *bn = child;

// 判断节点

while (bn)

{

if (T == bn) return level;


level++;

// 递归父级节点

bn = bn->parent;

}

return -1;

}


// 取得二叉树节点的根节点

binaryNode* getBinaryRoot(binaryNode *T)

{

if (!T) return NULL;


binaryNode *bn = T;

// 判断父级节点

while (bn->parent)

{

// 递归父级节点

bn = bn->parent;

}

return bn;

}


// 插入二叉树的子节点(右:1;左:0)

binaryNode* insertBinaryNode(binaryNode *T, int isRight, int key)

{

if (!T) return NULL;

// 判断是否已有左节点或右节点

if (isRight > 0)

{

if (T->right) return NULL;

}

else

{

if (T->left) return NULL;

}

// 创建二叉树节点

binaryNode *child = createBinaryNode(T->dataSize);

if (!child) return NULL;


// 节点关键字(优先数)

child->key = key;

// 父级节点

child->parent = T;

// 判断插入左节点或右节点

if (isRight > 0)

{

T->right = child;

child->isRight = 1;

}

else

{

T->left = child;

child->isRight = 0;

}

// 维护节点数量

binaryNode *bn = T;

// 判断节点

while (bn)

{

bn->length++;

// 递归父级节点

bn = bn->parent;

}

return child;

}


// 添加二叉树的子节点(右:1;左:0)

binaryNode* addBinaryNode(binaryNode *T, int isRight, binaryNode *child)

{

if ((!T) || (!child)) return NULL;

// 判断是否已有左节点或右节点

if (isRight > 0)

{

if (T->right) return NULL;

}

else

{

if (T->left) return NULL;

}

// 避免嵌套死循环,相对层级 >= 0,则表示嵌套子级节点

if (levelBinaryChildNode(child, T) >= 0) return NULL;

// 移除原有的父级关系

removeBinaryNode(child->parent, child);


child->parent = T;

// 判断添加左节点或右节点

if (isRight > 0)

{

T->right = child;

child->isRight = 1;

}

else

{

T->left = child;

child->isRight = 0;

}

// 维护节点数量

binaryNode *bn = T;

// 判断节点

while (bn)

{

bn->length += child->length;

// 递归父级节点

bn = bn->parent;

}

return child;

}


// 移除二叉树的子节点

int removeBinaryNode(binaryNode *T, binaryNode *child)

{

if ((!T) || (!child)) return -1;

// 判断父级关系是否匹配

if (T != child->parent) return -1;


int result = -1;

// 判断是否移除左节点

if (T->left == child)

{

T->left = NULL;

result = 1;

}

// 判断是否移除右节点

if (T->right == child)

{

T->right = NULL;

result = 1;

}


if (result > 0)

{

child->parent = NULL;

// 维护节点数量

binaryNode *bn = T;

// 判断节点

while (bn)

{

bn->length -= child->length;

// 递归父级节点

bn = bn->parent;

}

}

return result;

}


// 清空二叉树列表(递归)

void clearBinaryList(binaryNode *T)

{

if (!T) return;


// 递归清空左节点

clearBinaryList(T->left);

// 递归清空右节点

clearBinaryList(T->right);


// 释放数据空间

if (T->data) free(T->data);

// 释放自己

free(T);

}


// 层次遍历(输出数据的排序数组)

int levelOrder(binaryNode *T, binaryNode **orderList)

{

if ((!T) || (!orderList)) return -1;


linkQueue que;

// 初始化队列

initializeLinkQueue(&que);

// 根节点进队

pushQueue(&que, (int)T);


int index = 0;

binaryNode *bn;

// 进行队列操作

while (!isEmptyLinkQueue(que))

{

// 取得队首元素

bn = (int)front(que);

// 将队首元素出队

popQueue(&que);

// 判断元素是否有效

if (!bn) break;


// 排序数组赋值

orderList[index++] = bn;


// 左节点进队

if (bn->left) pushQueue(&que, (int)bn->left);

// 右节点进队

if (bn->right) pushQueue(&que, (int)bn->right);

}

// 清空队列

clearLinkQueue(&que);


return index;

}


// 前序遍历(递归)

int preOrderRecur(binaryNode *T, binaryNode **orderList, int index)

{

int i = index;

// 排序数组赋值

orderList[i++] = T;


// 递归左节点

if (T->left) i = preOrderRecur(T->left, orderList, i);

// 递归左节点

if (T->right) i = preOrderRecur(T->right, orderList, i);


return i;

}


// 前序遍历(递归)

int preOrderRecursion(binaryNode *T, binaryNode **orderList)

{

if ((!T) || (!orderList)) return -1;


// 前序遍历(递归)

return preOrderRecur(T, orderList, 0);

}


// 前序遍历(输出数据的排序数组)

int preOrder(binaryNode *T, binaryNode **orderList)

{

if ((!T) || (!orderList)) return -1;


linkStack stack;

// 初始化栈

initializeLinkStackSeq(&stack, BinaryTreeOrderBUFFER);

// 根节点进栈

push(&stack, (int)T);


int index = 0;

binaryNode *bn;

// 进行栈操作

while (!isEmptyLinkStack(stack))

{

// 取得栈首元素

bn = (int)top(stack);

// 将栈首元素出栈

pop(&stack);

// 判断元素是否有效

if (!bn) break;


// 排序数组赋值

orderList[index++] = bn;


// 右节点进栈

if (bn->right) push(&stack, (int)bn->right);

// 左节点进栈

if (bn->left) push(&stack, (int)bn->left);

}

// 清空栈

clearLinkStack(&stack);


return index;

}


// 中序遍历(递归)

int middleOrderRecur(binaryNode *T, binaryNode **orderList, int index)

{

int i = index;


// 递归左节点

if (T->left) i = middleOrderRecur(T->left, orderList, i);

// 排序数组赋值

orderList[i++] = T;

// 递归左节点

if (T->right) i = middleOrderRecur(T->right, orderList, i);


return i;

}


// 中序遍历(递归)

int middleOrderRecursion(binaryNode *T, binaryNode **orderList)

{

if ((!T) || (!orderList)) return -1;


// 中序遍历(递归)

return middleOrderRecur(T, orderList, 0);

}


// 中序遍历(输出数据的排序数组)

int middleOrder(binaryNode *T, binaryNode **orderList)

{

if ((!T) || (!orderList)) return -1;


linkStack stack, stackStatus;

// 初始化栈

initializeLinkStackSeq(&stack, BinaryTreeOrderBUFFER);

initializeLinkStackSeq(&stackStatus, BinaryTreeOrderBUFFER);

// 根节点进栈

push(&stack, (int)T);

push(&stackStatus, 0);


int index = 0, status;

binaryNode *bn;

// 进行栈操作

while (!isEmptyLinkStack(stack))

{

// 取得栈首元素

bn = (int)top(stack);

// 判断元素是否有效

if (!bn) break;


// 取得访问状态

status = (int)top(stackStatus);

pop(&stackStatus);


// 先访问左节点

if (status == 0)

{

push(&stackStatus, 1);

// 标记为0,尝试压栈左节点

if (bn->left)

{

push(&stack, (int)bn->left);

push(&stackStatus, 0);

}

}

else

{

// 将栈首元素出栈

pop(&stack);

// 排序数组赋值

orderList[index++] = bn;


// 尝试压栈右节点

if (bn->right)

{

push(&stack, (int)bn->right);

push(&stackStatus, 0);

}

}

}

// 清空栈

clearLinkStack(&stack);

clearLinkStack(&stackStatus);


return index;

}


// 后序遍历(递归)

int postOrderRecur(binaryNode *T, binaryNode **orderList, int index)

{

int i = index;


// 递归左节点

if (T->left) i = postOrderRecur(T->left, orderList, i);

// 递归左节点

if (T->right) i = postOrderRecur(T->right, orderList, i);


// 排序数组赋值

orderList[i++] = T;


return i;

}


// 后序遍历(递归)

int postOrderRecursion(binaryNode *T, binaryNode **orderList)

{

if ((!T) || (!orderList)) return -1;


// 后序遍历(递归)

return postOrderRecur(T, orderList, 0);

}


// 后序遍历(输出数据的排序数组)

int postOrder(binaryNode *T, binaryNode **orderList)

{

if ((!T) || (!orderList)) return -1;


linkStack stack, stackStatus;

// 初始化栈

initializeLinkStackSeq(&stack, BinaryTreeOrderBUFFER);

initializeLinkStackSeq(&stackStatus, BinaryTreeOrderBUFFER);

// 根节点进栈

push(&stack, (int)T);

push(&stackStatus, 0);


int index = 0, status;

binaryNode *bn;

// 进行栈操作

while (!isEmptyLinkStack(stack))

{

// 取得栈首元素

bn = (int)top(stack);

// 判断元素是否有效

if (!bn) break;


// 取得访问状态

status = (int)top(stackStatus);

pop(&stackStatus);


// 先左后右访问最低层节点

if (status == 0)

{

push(&stackStatus, 1);

// 标记为0,尝试压栈左节点

if (bn->left)

{

push(&stack, (int)bn->left);

push(&stackStatus, 0);

}

}

else if (status == 1)

{

push(&stackStatus, 2);

// 标记为1,尝试压栈右节点

if (bn->right)

{

push(&stack, (int)bn->right);

push(&stackStatus, 0);

}

}

else

{

// 将栈首元素出栈

pop(&stack);

// 排序数组赋值

orderList[index++] = bn;

}

}

// 清空栈

clearLinkStack(&stack);

clearLinkStack(&stackStatus);


return index;

}


// 在所有父级节点为空的元素中查找Key值(优先数)最小节点的索引下标

int minKeyIndex(binaryNode **nodeList, int len, int curIndex)

{

int i, min = -1;

binaryNode *bn;

// 倒序遍历已创建的二叉树节点列表

for (i = len - 1; i >= curIndex; i--)

{

bn = nodeList[i];

// 已设置父级节点,则无需比较

if (bn->parent) continue;

// 初始化最小值索引

if (min < 0) min = i;


// 比较Key值(优先数)最小节点的索引下标

if (bn->key < nodeList[min]->key) min = i;

}

return min;

}


// 生成最优二叉树(哈夫曼算法),返回二叉树根节点,参数传出叶子节点关系

binaryNode* bestBinaryTree(binaryNode *dataListOutleaf, int dataLen)

{

if ((!dataListOutleaf) || (dataLen < 2)) return NULL;

// 构造的最优二叉树,总数为叶子节点的两倍减一(dataLen * 2 - 1)

int len = dataLen * 2 - 1;

// 创建二叉树节点的缓存列表

binaryNode **nodeList = (binaryNode **)malloc(sizeof(binaryNode *) * len);

if (!nodeList) return NULL;


// 数据内容空间大小

int dataSize = dataListOutleaf[0].dataSize;

binaryNode *bn;


int index = len - 1, k;

// 循环创建二叉树节点,并倒序存储在列表中

for (k = 0; k < dataLen; k++)

{

// 创建二叉树节点

bn = createBinaryNode(dataSize);

if (!bn) continue;


// 优先数赋值

bn->key = dataListOutleaf[k].key;

// 设置二叉树节点的数据内容

setBinaryNodeData(bn, dataListOutleaf[k].data);


// 在列表中保存二叉树节点

nodeList[index--] = bn;

}


int minLeft, minRight, leafIndex;

binaryNode *leftNode, *rightNode;

// 数组左侧尚有未用空间,即新创建的节点个数还不足

while (index >= 0)

{

// 创建二叉树节点

bn = createBinaryNode(0);

if (!bn) continue;


// 在所有父级节点为空的元素中查找最小值的索引下标

minLeft = minKeyIndex(nodeList, len, index + 1);

leftNode = nodeList[minLeft];

// 添加二叉树的子节点(右:1;左:0)

addBinaryNode(bn, 0, leftNode);

// 如果是叶子节点,更新传入的基础数据列表的父级指针

if (isLeafBinaryNode(leftNode))

{

leafIndex = len - minLeft - 1;

dataListOutleaf[leafIndex].parent = bn;

dataListOutleaf[leafIndex].isRight = 0;

}


// 在所有父级节点为空的元素中查找最小值的索引下标

minRight = minKeyIndex(nodeList, len, index + 1);

rightNode = nodeList[minRight];

// 添加二叉树的子节点(右:1;左:0)

addBinaryNode(bn, 1, rightNode);

// 如果是叶子节点,更新传入的基础数据列表的父级指针

if (isLeafBinaryNode(rightNode))

{

leafIndex = len - minRight - 1;

dataListOutleaf[leafIndex].parent = bn;

dataListOutleaf[leafIndex].isRight = 1;

}


// 新创建的节点Key值(优先数)

bn->key = (leftNode->key + rightNode->key);

// 在列表中保存二叉树节点

nodeList[index--] = bn;

}

// 释放缓存列表

free(nodeList);


return bn;

}


// 取得哈夫曼编码(叶子节点列表),注意在外部释放每个hfCode的内存空间

char** getHuffmanCodeByLeaf(binaryNode *leafList, int leafLen, char **hfCodeList)

{

if ((!leafList) || (!hfCodeList) || (leafLen < 2)) return NULL;

// 定义一个字符串缓存

char *tmp = (char *)malloc(sizeof(char) * leafLen);

if (!tmp) return NULL;


binaryNode *bn;

char *code;

int i, index;

// 为每个hfCode申请内存空间

for (i = 0; i < leafLen; i++)

{

code = (char *)malloc(sizeof(char) * leafLen);

if (!code) return NULL;


bn = &(leafList[i]);

index = 0;

// 开始记录编码

while (bn->parent)

{

tmp[index++] = bn->isRight + '0';

// 递归父级节点

bn = bn->parent;

}

// 补充结束符

tmp[index] = 0;


// 字符串逆序输出

myReverse(tmp, code);

// 保存hfCode

hfCodeList[i] = code;

}

// 释放缓存

free(tmp);


return hfCodeList;

}


// 取得哈夫曼编码,注意在外部释放每个hfCode的内存空间

char** getHuffmanCode(binaryNode *dataList, int dataLen, char **hfCodeList)

{

// 生成最优二叉树(哈夫曼算法),返回二叉树根节点,参数传出叶子节点关系

binaryNode *root = bestBinaryTree(dataList, dataLen);

if (!root) return NULL;


// 取得哈夫曼编码(叶子节点列表)

char **result = getHuffmanCodeByLeaf(dataList, dataLen, hfCodeList);

// 释放二叉树列表

clearBinaryList(root);


return result;

}


以上是关于数据结构的实践心得(二叉树的抽象数据结构和各种遍历的递归及非递归实现,以及哈夫曼算法应用:binaryTree)的主要内容,如果未能解决你的问题,请参考以下文章

记数据结构MOOC-二叉树

求数据结构做二叉树实验的心得体会、、、

数据结构-二叉树的存储结构与遍历

数据结构二叉树及其各种遍历

C#实现二叉树的各种遍历

考研计算机 | 二叉树