当前位置: 代码迷 >> 综合 >> 数据结构 - 二叉树的实现与操作
  详细解决方案

数据结构 - 二叉树的实现与操作

热度:73   发布时间:2024-02-02 10:27:25.0

1、二叉树的表示法

1.1、二叉链表示法

数据结构定义: 

//1 - 二叉链表示法//节点类型为int
typedef struct BiTNode
{int data;struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;//节点类型为char
typedef struct BiTNodeC
{char data;struct BiTNodeC *lchild, *rchild;
}BiTNodeC, *BiTreeC;

实现:

void play01_2()
{BiTNode *pt1, *pt2, *pt3, *pt4, *pt5;pt1 = (BiTree) malloc(sizeof(BiTNode));	pt2 = (BiTree)malloc(sizeof(BiTNode));	pt3 = (BiTree)malloc(sizeof(BiTNode));pt4 = (BiTree)malloc(sizeof(BiTNode));	pt5 = (BiTree)malloc(sizeof(BiTNode));pt1->data = 1;	pt2->data = 2;	pt3->data = 3;pt4->data = 4;	pt5->data = 5;//表达二叉树pt1->lchild = pt2;	pt1->rchild = pt3;pt2->lchild = pt4;pt3->lchild = pt5;//free(pt1); free(pt2); free(pt3); free(pt4); free(pt5);
}

 

1.2、三叉链表示法

和二叉链表示法相比,多了一个指向父节点的指针。 

//2 - 三叉链表示法
typedef struct TriTNode
{int data;struct BiTNode *lchild, *rchild;struct BiTNode *parent;			//多了一个指向父节点的指针
}TriTNode, *TriTree;

1.3、双亲链表表示法

数据结构定义: 

//3 - 双亲链表表示法(子节点中保存了双亲节点的位置)
#define MAX_TREE_SIZE 100
typedef struct BPTNode
{int data;int parentPosition;	//指向双亲的指针(双亲数组下标)char LRTag;			//左右孩子标志域 L或R
}BPTNode;typedef struct BPTree
{BPTNode nodes[MAX_TREE_SIZE];	//因为节点之间是分散的,需要把节点存储到数组中int num_node;					//节点的数目int root;						//根节点的位置,注意此域存储的是父亲节点在数组的下标
}BPTree;

实现:

void play01_3()
{BPTree tree;	//定义树tree.root = 0;	//根节点位置tree.num_node = 5;//给树的元素赋值//根节点tree.nodes[0].data = 1;//tree.nodes[1].data = 2;tree.nodes[1].parentPosition = 0;tree.nodes[1].LRTag = 'L';tree.nodes[2].data = 3;tree.nodes[2].parentPosition = 0;tree.nodes[2].LRTag = 'R';for (int i = 0; i < 3; i++){cout << tree.nodes[i].data << endl;}
}

 

2、创建树

2.1、#法创建树

BiTreeC createTree2(const char *s)
{BiTreeC node = nullptr;//1## - 先序字符串static int cur_index = 0;char ch = s[cur_index];cur_index++;if (ch == '#'){return nullptr;}else{node = (BiTreeC)malloc(sizeof(BiTNodeC));if (nullptr == node)	return nullptr;memset(node, 0, sizeof(BiTNodeC));node->data = ch;node->lchild = createTree2(s);node->rchild = createTree2(s);}return node;
}const char *s = "ABDH#K###E##CFI###G#J##";    //先序字符串
BiTreeC p = nullptr;
p = createTree2(s);

2.2、中序和先序创建树

基本思想:

中序和先序创建树 算法:

1、通过先序遍历结果中找到根节点root,再通过root在中序遍历结果中找出左子树(左侧)、右子树(右侧)

2、在root的左子树中,找出左子树的根节点(在先序结果中中找),转步骤1;

3、在root的右子树中,找出右子树的根节点(在先序结果中中找),转步骤1;

const string g_pre_str = "ADEBCF";
const string g_in_str = "DEACFB";string split_left(const string root_str, const char& root)
{if (root_str.size() == 1){return "";}string in_str = root_str;string left = in_str.substr(0, in_str.find(root));return left;
}string split_right(const string root_str, const char& root)
{string in_str = root_str;if (root_str.size() == 1 || in_str.find(root) >= in_str.length()-1){return "";}string right = in_str.substr(in_str.find(root) + 1, in_str.length());return right;
}char getRoot(const string root_str)
{size_t pre_index = g_pre_str.length();for (size_t i = 0; i < root_str.length(); i++){size_t tmp = g_pre_str.find(root_str.at(i));pre_index < tmp ? pre_index : pre_index = tmp;}return g_pre_str.at(pre_index);
}BiTreeC createTree_in_and_pre(const string root_str)
{BiTreeC node = nullptr;if (root_str.empty()){return nullptr;}char root = getRoot(root_str);if ('\0' == root){return nullptr;}node = (BiTreeC)malloc(sizeof(BiTNodeC));memset(node, 0, sizeof(BiTNodeC));node->data = root;string left_str = split_left(root_str, root);string right_str = split_right(root_str, root);node->lchild = createTree_in_and_pre(left_str);node->rchild = createTree_in_and_pre(right_str);return node;
}
const char *pre = "ADEBCF";
const char *in = "DEACFB";
BiTreeC p = nullptr;
p = createTree_in_and_pre(g_in_str);

 2.3、销毁树

先序创建树则后续销毁。

void freeTree(BiTreeC t)
{if (nullptr == t)return;if (nullptr != t->lchild){freeTree(t->lchild);	t->lchild = nullptr;}if (nullptr != t->rchild){freeTree(t->rchild);	t->rchild = nullptr;}if(t){free(t);t = nullptr;}return;
}

3、二叉树的遍历

 

3.1、先序遍历

先序遍历:中左右

//先序遍历
void preOrder(BiTNode* root)
{if (nullptr == root){return;}//打印根节点cout << root->data << " ";//然后 遍历左子树preOrder(root->lchild);//最后 遍历右子树preOrder(root->rchild);return;
}

3.2、中序遍历

中序遍历:左中右

//中序遍历
void inOrder(BiTNode* root)
{if (nullptr == root){return;}//先 遍历左子树inOrder(root->lchild);//然后 打印根节点的值cout << root->data << " ";//最后 遍历右子树inOrder(root->rchild);return;
}

3.3、后序遍历

后序遍历:左右中

//后序遍历
void postOrder(BiTNode* root)
{if (nullptr == root){return;}//先 遍历左子树postOrder(root->lchild);//然后 遍历右子树postOrder(root->rchild);//最后 打印根节点的值cout << root->data << " ";return;
}

3.4、树的非递归遍历

树的非递归遍历(中序遍历),算法基本思想:

中序遍历的几种情况:
分析1:什么时候访问根?什么时候访问左子树?什么时候访问右子树?
当左子树为空或者左子树已经访问完毕,再访问根;
访问根之后,再访问右子树;

分析2:为什么是栈,而不是其他(比如 队列)
先走到的后访问,后走到的先访问,显示是站结构

分析3:节点所有路径情况
步骤1: 找到中序遍历的起点
如果节点 有 左子树,该节点入栈,继续找下一个左子树;
如果该节点 没有 左子树,访问该节点;
步骤2:
如果节点 有 右子树,走到右子树的根节点,重复步骤1;
如果节点 没有 右子树(节点访问完毕),根据栈顶指示访问栈顶元素,并回退;
如果栈为空,表示遍历结束;

注意:入栈的节点表示,本身没有被访问过,同时右子树也没有被访问过。

using TreeStack = stack<BiTreeC>;//步骤①:向左走,直到找到中序遍历的起点
BiTreeC goLeft(BiTreeC root, TreeStack &stack)
{if (nullptr == root){return nullptr;}while (nullptr != root->lchild){stack.push(root);		//先压栈(节点有左子树)root = root->lchild;	//然后继续找左子树}cout << root->data << " ";	//节点没有左子树,直接访问该节点return root;
}//中序 非递归 遍历
void InOrder_stack(BiTreeC root)
{if (nullptr == root){return;}TreeStack stack;BiTreeC t = goLeft(root, stack);while (t){if (nullptr != t->rchild){//如果有右子树,则执行步骤①t = goLeft(t->rchild, stack);}else if(nullptr == t->rchild && !stack.empty()){//如果没有右子树,根据栈顶提示 回退,t = stack.top();stack.pop();//打印cout << t->data << " ";}else{t = nullptr;}}
}

4、树的操作

4.1、求树的高度

int treeDepth(BiTNode* root)
{int leftDepth = 0;int rightDepth = 0;int depth = 0;if (nullptr == root){return depth;}//左子树高度leftDepth = treeDepth(root->lchild);//右子数高度rightDepth = treeDepth(root->rchild);depth = 1 + (leftDepth>rightDepth?leftDepth:rightDepth);return depth;
}

4.2、copy树

BiTree treeCopy(BiTNode* root)
{BiTree newNode = nullptr;BiTree newLeft = nullptr;BiTree newRight = nullptr;if (nullptr == root)return root;newLeft = treeCopy(root->lchild);newRight = treeCopy(root->rchild);//效果与下面等同,因为上面已经判断了 nullptr == root 的情况/*	//该代码也可正常运行if (root->lchild){newLeft = treeCopy(root->lchild);}elsereturn nullptr;if (root->rchild){newRight = treeCopy(root->rchild);}elsereturn nullptr;*/newNode = (BiTree)malloc(sizeof(BiTNode));if (!newNode)return nullptr;newNode->lchild = newLeft;newNode->rchild = newRight;newNode->data = root->data;return newNode;
}