「データ構造列」
記事ディレクトリ
1. ツリー構造を理解する
ツリーの定義: ツリーとは、N (N>=0) 個の有限ノードで構成される階層関係の集合を指し、単純な非線形構造です。N=0 の場合、空のツリーと呼ばれます。
木を横切る方法
前序遍历
中序遍历
后序遍历
前-中-後-順序トラバーサルの場合、ルート ノードの位置を使用して前順序が決定されます。
层序遍历
層シーケンスの場合、層ごとに巡回され、上位層のルート ノードを巡回した後に次の層のノード データが取り込まれます。補助キューのコンテナを使用して、順次トラバーサルを実装できます。
代码实现
//层序遍历
void BinaryTreeLevelOrder(BTNode* root)
{
Queue qu;
BTNode* cur;
QueueInit(&qu);
QueuePush(&qu, root);
while (! QueueEmpty(&qu))
{
cur = QueueFront(&qu);
putchar(cur->_data);
if (cur->_left)
{
QueuePush(&qu, cur->_left);
}
if (cur->_right)
{
QueuePush(&qu, cur->_right);
}
QueuePop(&qu);
}
QueueDestory(&qu);
}
ツリーを作成するにはどうすればよいですか?
二分木の走査は、前次、中次、後次の走査です。事前順序および事後順序トラバーサルの場合、ルート ノードを迅速に見つけることができます。次に、inorder によって左右のサブツリーを区別します。ツリーの構築を実現します。
编一个程序,读入用户输入的一串先序遍历字符串,根据此字符串建立一个二叉树(以指针方式存储)。 例如如下的先序遍历字符串: ABC##DE#G##F### 其中“#”表示的是空格,空格字符代表空树。建立起此二叉树以后,再对二叉树进行中序遍历,输出遍历结果。
入力: abc ## de #g ## f ###
出力: cbegdfa
ツリーを構築する場合、
入力はデータ ストレージ用の配列であるため、ツリー ノードを構築するときにデータ レコード配列の添字を使用する必要があります。
再帰中に配列の添字を使用した後、添字をリセットするために戻ることは避けてください。ここでは、配列の添字の一貫性を維持し、後方に進む必要があります。再帰が発生した後でのみ、配列全体が走査されます。前文の思考構築ツリーが使用されます。
typedef struct TreeNode
{
struct TreeNode* left;
struct TreeNode* right;
char val;
}TreeNode;
TreeNode* makeTree(char* arr,int *count)
{
if(arr[*count]=='#'||arr[*count]==' ')
{
return NULL;
}
TreeNode* newnode=(TreeNode*)malloc(sizeof(TreeNode));
newnode->val=arr[(*count)++];
newnode->left=makeTree(arr, count);
(*count)++;
newnode->right=makeTree(arr, count);
return newnode;
}
void InOrder(TreeNode*root)
{
if(root==NULL)
return ;
InOrder(root->left);
printf("%c ",root->val);
InOrder(root->right);
}
int main()
{
char arr[101];
scanf("%s",arr);
int count=0;
TreeNode*tree=makeTree(arr, &count);
InOrder(tree);
return 0;
}
木が完全な二分木であるかどうかを判断するにはどうすればよいでしょうか?
完全な二分木と完全な二分木を比較すると、完全な二分木の下端の葉ノードの数は左から右に減少するため、高さ n-1 の層の数は同じになります。完全なバイナリ ツリー: 分析用の完全なバイナリ ツリー層の最後のもの。
n 個のノードを持つ完全なバイナリ ツリーの場合、配列の上から下、左から右の順序に従ってすべてのノードに 0 から番号が付けられている場合、シーケンス番号 i のノードについては次のようになります
。
- i>0 の場合、i 位置のノードの親番号: (i-1)/2; i=0、i はルート ノード番号、親ノードなし
- 2i+1<n の場合、左の子の番号: 2i+1, 2i+1>=n それ以外の場合、左の子はありません
- 2i+2<n の場合、右側の子の番号: 2i+2, 2i+2>=n それ以外の場合は右側の子はありません
代码实现
int BinaryTreeComplete(BTNode* root)
{
Queue qu;
BTNode* cur;
int tag = 0;
QueueInit(&qu);
QueuePush(&qu, root);
while (! QueueEmpty(&qu))
{
cur = QueueFront(&qu);
putchar(cur->_data);
if (cur->_right && !cur->_left)
{
return 0;
}
if (tag && (cur->_right || cur->_left))
{
return 0;
}
if (cur->_left)
{
QueuePush(&qu, cur->_left);
}
if (cur->_right)
{
QueuePush(&qu, cur->_right);
}
else
{
tag = 1;
}
QueuePop(&qu);
}
BinaryTreeDestory(&qu);
return 1;
}
2、ツリーの単純なアルゴリズム - 再帰
1. 同じ木
给你两棵二叉树的根节点 p 和 q ,编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同,并且节点具有相同的值,则认为它们是相同的
ノードデータは同じデータであり、左右のサブツリー構造も同じであるということを同じ理解として、片方のツリーが空で、もう片方のツリーが空であるかどうかの判断についても議論する必要があります。ツリーは空ではありませんが、明らかにそうではありません。同じ数です。判定条件は、val値、左右の部分木構造が同時に空であるかどうか(全て葉ノードであるかどうかの判定)である。
class Solution {
public:
bool isSameTree(TreeNode* p, TreeNode* q) {
if(p==nullptr&&q==nullptr)return true;
if(p==nullptr||q==nullptr)return false;
if(q->val!=p->val)return false;
return isSameTree(q->left,p->left)&&isSameTree(q->right,p->right);
}
};
2. ミラーツリー
给你一个二叉树的根节点 root , 检查它是否轴对称
鏡像ツリーとその解は上記の同じツリーと多少似ていますが、ツリー構造の比較では左のサブツリーと右のサブツリーが対称であり、同じツリーのロジックを使用して比較が行われるという点でわずかな違いがあります。問題を解く。
class Solution {
public:
bool issametree(TreeNode* root,TreeNode* subroot)
{
if(root==nullptr && subroot==nullptr)
{
return true;
}
if(root==nullptr || subroot==nullptr)
{
return false;
}
if(root->val==subroot->val)
{
return issametree(root->left,subroot->right) && issametree(root->right,subroot->left);
}
else
{
return false;
}
}
bool isSymmetric(TreeNode* root) {
if(root==nullptr) return true;
return issametree(root->left,root->right);
}
};
3. 単一値二分木
トピック:
如果二叉树每个节点都具有相同的值,那么该二叉树就是单值二叉树。 只有给定的树是单值二叉树时,才返回 true;否则返回 false。
これは、深さトラバーサルを使用して、左のサブツリーから右のサブツリーまで順番にトラバースして、バイナリ ツリー内の値を見つける比較的一般的なアルゴリズムです。ノード データを追加した後は、左右のサブツリーを比較することはできません。左側には複数のノードがあり、右側にはノード データが 1 つだけあります。ただし、左と右のサブツリーの値は依然として等しいです。したがって、左右のサブツリーを比較して判断するには、ルートから va を取得する必要があります。
class Solution {
public:
bool isUnivalTree(TreeNode* root) {
if(root==nullptr)return true;
if(root->left&&root->val!=root->left->val)
return false;
if(root->right&&root->val!=root->right->val)
return false;
return isUnivalTree(root->left)&&isUnivalTree(root->right);
}
};
要約する
ツリーの構造は再帰アルゴリズムを使用して走査することで理解しやすくなりますが、ツリーが深すぎるとスタック オーバーフローが発生します。首が曲がったツリーや単一のツリーが出現する傾向があるため、ツリーはデータの保存には明らかに適していません。効率が低い。後で最適化して、検索バイナリ ツリーや AVL ツリーにすることもできます。