参考:1.数据结构C语言版|第2版;2.力扣;3.2024年数据结构考研复习指导。三个参考分别依次对应文章三个部分。
文章目录
第一部分
基本概念
树是 n ( n ≥ 0 ) n(n\geq0) n(n≥0)个结点的有限集,它或为空树 ( n = 0 ) (n=0) (n=0);或为非空树,对于非空树T:(1)有且仅有一个称之为根的结点;(2)除根结点以外的其余节点可分为 m ( m > 0 ) m(m>0) m(m>0)个互不相交的有限集 T 1 , T 2 , ⋯ , T m T_1,T_2,\cdots,T_m T1,T2,⋯,Tm,其中每一个集合本身又是一棵树,并且称为根的子树。重要术语:孩子、双亲(PS:说双亲但是实际只有一个)、兄弟、祖先、子孙、叶子或者终端结点、内部结点或者非终端结点、结点的度、树的度、树的高度或者深度、有序树、无序树、森林。 二叉树是 n ( n ≥ 0 ) n(n\geq0) n(n≥0)个结点所构成的集合,它或为空树 ( n = 0 ) (n=0) (n=0);或为非空树,对于非空树T:(1)有且仅有一个称之为根的结点;(2)除根结点以外的其余结点分为两个互不相交的子集 T 1 T_1 T1和 T 2 T_2 T2,分别称为T的左子树和右子树,且 T 1 T_1 T1和 T 2 T_2 T2本身又都是二叉树。满二叉树: 深度为k且含有 2 k − 1 2^k-1 2k−1个结点的二叉树。完全二叉树: 深度为k的,有n个结点的二叉树,当且仅当其每一个结点都与深度为k的满二叉树中编号从1至n的结点一一对应时,称之为完全二叉树。
基本性质
性质1: 在二叉树的第 i i i层上至多有 2 i − 1 2^{i-1} 2i−1个结点 ( i ≥ 1 ) (i\geq1) (i≥1)。性质2: 深度为k的二叉树至多有 2 k − 1 2^k-1 2k−1个结点 ( k ≥ 1 ) (k\geq 1) (k≥1)。性质3: 对任何一棵二叉树T,如果其终端结点数为 n 0 n_0 n0,度为2的结点数为 n 2 n_2 n2,则 n 0 = n 2 + 1 n_0=n_2+1 n0=n2+1。性质4: 具有n个结点的完全二叉树的深度为 ⌊ l o g 2 n ⌋ + 1 \lfloor log_2^n\rfloor+1 ⌊log2n⌋+1。性质5: 如果对一棵有n个结点的完全二叉树的结点按层序编号,则对任一结点 i ( 1 ≤ i ≤ n ) i(1\leq i\leq n) i(1≤i≤n),有(1)如果 i = 1 i=1 i=1,则结点 i i i是二叉树的根,无双亲;如果 i > 1 i>1 i>1,则其双亲 P A R E N T ( i ) PARENT(i) PARENT(i)是节点 ⌊ i / 2 ⌋ \lfloor i/2\rfloor ⌊i/2⌋。(2)如果 2 i > n 2i>n 2i>n,则结点 i i i无左孩子(结点 i i i为叶子结点);否则其左孩子 L C H I L D ( i ) LCHILD(i) LCHILD(i)是结点 2 i 2i 2i。(3)如果 2 i + 1 > n 2i+1>n 2i+1>n,则结点 i i i无右孩子;否则其右孩子 R C H I L D ( i ) RCHILD(i) RCHILD(i)是结点 2 i + 1 2i+1 2i+1。(注意与代码的区别)
存储结构
顺序存储
首先用0补充成完全二叉树,然后从上到下从左只有写吧。
链式存储
struct TreeNode {
int val;
TreeNode *left;
TreeNode *right;
};
经典应用1
遍历
前序遍历
递归
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> result;
vector<int> preorderTraversal(TreeNode* root) {
PreOrder(root);
return result;
}
void PreOrder(TreeNode * root)
{
if (!root) return;
result.push_back(root->val);
PreOrder(root->left);
PreOrder(root->right);
}
};
非递归
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> result;
if (!root) return result;
stack<TreeNode *> z;
z.push(root);result.push_back(root->val);
while (!z.empty())
if (z.top()->left)
{
TreeNode * temp=z.top()->left;z.top()->left=nullptr;
z.push(temp);result.push_back(temp->val);
}
else if (z.top()->right)
{
TreeNode * temp=z.top()->right;z.top()->right=nullptr;
z.push(temp);result.push_back(temp->val);
}
else z.pop();
return result;
}
};
中序遍历
递归
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> result;
vector<int> inorderTraversal(TreeNode* root) {
InOrder(root);
return result;
}
void InOrder(TreeNode * root)
{
if (!root) return;
InOrder(root->left);
result.push_back(root->val);
InOrder(root->right);
}
};
非递归
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> result;
if (!root) return result;
stack<TreeNode *> z;
z.push(root);
while (!z.empty())
if (z.top()->left)
{
TreeNode * temp=z.top()->left;z.top()->left=nullptr;z.push(temp);
}
else
{
result.push_back(z.top()->val);
if (z.top()->right)
{
TreeNode * temp=z.top()->right;z.pop();z.push(temp);
}
else z.pop();
}
return result;
}
};
后序遍历
递归
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> result;
vector<int> postorderTraversal(TreeNode* root) {
PostOrder(root);
return result;
}
void PostOrder(TreeNode * root)
{
if (!root) return;
PostOrder(root->left);
PostOrder(root->right);
result.push_back(root->val);
}
};
非递归
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> result;
if (!root) return result;
stack<TreeNode *> z;
z.push(root);
while (!z.empty())
if (z.top()->left)
{
TreeNode * temp=z.top()->left;z.top()->left=nullptr;z.push(temp);
}
else if (z.top()->right)
{
TreeNode * temp=z.top()->right;z.top()->right=nullptr;z.push(temp);
}
else {result.push_back(z.top()->val);z.pop();}
return result;
}
};
层序遍历
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<vector<int>> levelOrder(TreeNode* root) {
vector<vector<int>> lb;
if (!root) return lb;
queue<TreeNode *> dl;
dl.push(root);
while (!dl.empty())
{
queue<TreeNode *> temp_dl;
vector<int> temp_lb;
while (!dl.empty())
{
TreeNode * temp_node=dl.front();dl.pop();
if (temp_node->left) temp_dl.push(temp_node->left);
if (temp_node->right) temp_dl.push(temp_node->right);
temp_lb.push_back(temp_node->val);
}
lb.push_back(temp_lb);
dl=temp_dl;
}
return lb;
}
};
建树
先序序列加上中序序列可以建立唯一的二叉树。
后序序列加上中序序列可以建立唯一的二叉树。
先序序列加上后序序列不能建立唯一的二叉树。
根据先序序列加上中序序列建立二叉树
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> lb1,lb2;
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
lb1=preorder;lb2=inorder;
TreeNode * result=new TreeNode;
traverse(result,0,lb1.size()-1,0,lb2.size()-1);
return result;
}
void traverse(TreeNode * node,int l1,int r1,int l2,int r2)
{
node->val=lb1[l1];
int m;
for (int i=l2;i<=r2;i++)
if (lb2[i]==node->val)
{
m=i;break;
}
if (m!=l2)
{
node->left=new TreeNode;
traverse(node->left,l1+1,l1+m-l2,l2,m-1);
}
if (m!=r2)
{
node->right=new TreeNode;
traverse(node->right,l1+m-l2+1,r1,m+1,r2);
}
}
};
根据后序序列加上中序序列建立二叉树
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
vector<int> lb1,lb2;
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
lb1=postorder;lb2=inorder;
TreeNode * result=new TreeNode;
traverse(result,0,lb1.size()-1,0,lb2.size()-1);
return result;
}
void traverse(TreeNode * node,int l1,int r1,int l2,int r2)
{
node->val=lb1[r1];
int m;
for (int i=l2;i<=r2;i++)
if (lb2[i]==node->val)
{
m=i;break;
}
if (m!=l2)
{
node->left=new TreeNode;
traverse(node->left,l1,r1-(r2-m)-1,l2,m-1);
}
if (m!=r2)
{
node->right=new TreeNode;
traverse(node->right,r1-(r2-m),r1-1,m+1,r2);
}
}
};
计算
计算树的最小深度
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int minDepth(TreeNode* root) {
if (!root) return 0;
if (!root->left) return minDepth(root->right)+1;
if (!root->right) return minDepth(root->left)+1;
if (!root->left and !root->right) return 0;
return min(minDepth(root->left),minDepth(root->right))+1;
}
};
计算树的最大深度
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
int maxDepth(TreeNode* root) {
if (!root) return 0;
return max(maxDepth(root->left),maxDepth(root->right))+1;
}
};
杂七杂八
线索二叉树的特点:若节点有左子树,则lchild域指示其左孩子,否则lchild指示其前驱;若节点有右子树,则rchild域指示其右孩子,否则rchild指示其后继。 注意前驱后继含义。
树的经典表示方法:
双亲表示
用node数组
struct node
{
char s;
int prev;
};
孩子表示
用node数组
struct next
{
int position;
next * brother;
};
struct node
{
char s;
next * child;
};
孩子表示还有一种就是用度表示那种。
孩子兄弟
二叉链表
struct node
{
int value;
node * firstchild;
node * nextbrother;
};
森林转二叉树: 1.每个结点左指针指向它的从左向右的第一个孩子,右指针指向它的右兄弟。;2.第一棵树根节点的右指针指向第二棵树的根节点,以此类推。
二叉树转森林: 1.反向森林转二叉树2;2.反向森林转二叉树1。
经典应用2
Huffman树编码及其解码
输入样例
5
1 2 3 4 5
010011001011
输出样例
010
011
00
10
11
abcde
#include<iostream>
#include<vector>
#include<string>
#include<unordered_map>
using namespace std;
int n;
vector<int> lt1;
struct Node
{
int x=-1;
Node * l=nullptr;
Node * r=nullptr;
};
vector<Node *> lt2;
pair<Node *,Node *> function1()
{
vector<Node *>::iterator zz1=lt2.begin(),zz2=lt2.begin()+1;
if ((*zz1)->x>(*zz2)->x)
{
vector<Node *>::iterator zz_temp=zz1;zz1=zz2;zz2=zz_temp;
}
for (vector<Node *>::iterator zz3=lt2.begin()+2;zz3!=lt2.end();zz3++)
if ((*zz3)->x<=(*zz1)->x) {zz2=zz1;zz1=zz3;}
else if ((*zz3)->x<(*zz2)->x) zz2=zz3;
//这样做使huffman树唯一
Node * zz1node=*zz1;Node * zz2node=*zz2;
bool x=zz1<zz2?1:0;
lt2.erase(zz1);
if (x) lt2.erase(zz2-1);
else lt2.erase(zz2);
if (x) return make_pair(zz1node,zz2node);
return make_pair(zz2node,zz1node);
}
void create()
{
for (int i=0;i<n-1;i++)
{
Node * nodel;Node * noder;
pair<Node *,Node *> temp=function1();
nodel=temp.first;noder=temp.second;
Node * node_father=new Node;
node_father->x=nodel->x+noder->x;
node_father->l=nodel;
node_father->r=noder;
lt2.push_back(node_father);
}
}
typedef Node * Tree;
unordered_map<int,string> zd;
//构建字典
void function2(Node * node,string s)
{
if (node->l==nullptr and node->r==nullptr)
{
zd[node->x]=s;return;
}
if (node->l!=nullptr) function2(node->l,s+'0');
if (node->r!=nullptr) function2(node->r,s+'1');
}
int function4(int x)
{
for (int i=0;i<n;i++)
if (lt1[i]==x)
return i;
return -1;
}
void function3(Node * node)
{
string s;cin>>s;Node * temp=node;
for (int i=0;i<s.size();i++)
{
if (s[i]=='0') temp=temp->l;
else temp=temp->r;
if (temp->l==nullptr and temp->r==nullptr)
{
int x=function4(temp->x);
cout<<char('a'+x)<<flush;
temp=node;
}
}
}
int main()
{
//n大于等于2;
cin>>n;
for (int i=0;i<n;i++)
{
int x;cin>>x;
lt1.push_back(x);
Node * node=new Node;node->x=x;lt2.push_back(node);
}
create();
Tree root=lt2[0];
string s;
function2(root,s);
for (int x:lt1) cout<<zd[x]<<endl;
function3(root);
return 0;
}
感觉严书这有点乱,我是按照严书写的。
第二部分
会了上面经典应用,这一部分也就会了。
就不做其他题目了。
第三部分
老实做吧,不多评价。
PS:
⌊
l
o
g
2
n
⌋
+
1
=
⌈
l
o
g
2
n
+
1
⌉
,
n
∈
N
∗
.
\lfloor log_2^n \rfloor+1 =\lceil log_2^{n+1} \rceil,n\in N^*.
⌊log2n⌋+1=⌈log2n+1⌉,n∈N∗.