一,将二叉搜索树转换为一个排序的双向链表。
提示:要求不能创建任何新的结点,只能调整树中节点的指向。
eg:
搜索二叉树:左节点的值小于父节点的值,右节点的值大于父节点的值。
思路:二叉树中每个节点有两个指向子节点的指针,双向链表中每个节点也有两个指针,两个节点结构相似,同时二叉搜索树也是一种排序的数据结构。因此理论上可能实现二叉搜索树和排序双向链表的转换。
步骤:在将二叉搜索树转换为排序双向链时,原先指向左子节点的指针调为链表中指向前一个节点的指针,原先指向右子节点的指针调为链表中指向后一个节点的指针。
按照中序遍历的顺序,当我们遍历转换到根节点时,它的左子树已经转换为一个排序的链表,并且处在链表中最后一个节点的是当前最大值的节点。把8和根节点连接起来,此时链表中最后一个节点就是10,接着去遍历转换右子树,并把根节点和右子树中最小的节点连接起来。
代码实现:
#include<iostream>
#include<Windows.h>
using namespace std;
//定义二叉树节点结构
struct BSTNode
{
BSTNode* _left;
BSTNode* _right;
int _data;
BSTNode(int data,BSTNode* left = NULL,BSTNode* right = NULL)
:_data(data)
,_left(left)
,_right(right)
{}
};
//插入新节点到树中
void Insert(BSTNode*& tree,int data)
{
if(NULL == tree)
{
tree = new BSTNode(data,NULL,NULL);
}
else if(data < tree->_data)
{
Insert(tree->_left,data);
}
else if(data > tree->_data)
{
Insert(tree->_right,data);
}
else
{
return ;
}
}
//查找二叉搜索树tree的最左节点
BSTNode* Findleftnode(BSTNode* tree)
{
if(tree == NULL)
{
return NULL;
}
while(tree->_left != NULL)
{
tree = tree->_left;
}
return tree;
}
//遍历二叉树的各个节点,并进行指针调解
void ConvertNode(BSTNode* tree,BSTNode*& lastnodeList)
{
if(tree == NULL)
{
return;
}
if(tree->_left != NULL)//将左子树进行转换
{
ConvertNode(tree->_left,lastnodeList);
}
tree->_left = lastnodeList;
if(lastnodeList != NULL)//调整最后一个节点的指针,使它指向此时的父节点
{
lastnodeList->_right = tree;
}
lastnodeList = tree;
if(tree->_right != NULL)//将右子树进行转换
{
ConvertNode(tree->_right,lastnodeList);
}
}
//将二叉搜索树tree转化为双向链表,并返回头结点
BSTNode* BSTNodetolist(BSTNode* tree)
{
if(tree == NULL)
{
return NULL;
}
BSTNode* head = Findleftnode(tree);//将二叉树最左边的节点转化为链表的头结点
BSTNode* lastnodeList = NULL;
ConvertNode(tree,lastnodeList);//进行转换
return head;
}
//以中序遍历打印二叉搜索树tree
void Printtree(BSTNode* tree)
{
if(tree == NULL)
{
return;
}
Printtree(tree->_left);
cout<<tree->_data<<" ";
Printtree(tree->_right);
}
//打印链表
void PrintList(BSTNode* head)
{
if(head == NULL)
{
return;
}
BSTNode* node = head;
while(node!=NULL)
{
cout<<node->_data<<" ";
node = node->_right;
}
cout<<endl;
}
int main()
{
BSTNode* tree = NULL;
int a[] = {10,6,14,4,8,12,16};
for(size_t i = 0;i<(sizeof(a)/sizeof(a[0]));i++)
{
Insert(tree,a[i]);
}
Printtree(tree);
cout<<endl;
BSTNode* head = BSTNodetolist(tree);
PrintList(head);
return 0;
}
2.判断一棵树是否是完全二叉树
完全二叉树的概念:设二叉树的深度是h,除了最后一层其它层的节点数达到最大个数,第h层所有的节点都连续集中在最左边。
思路:层序遍历思想,利用队列queue实现。
考虑到四种不同的情况:
(1)如果树为空,直接返回false
(2)如果一个节点的左右孩子均不为空,pop掉该节点,将其左右孩子入队列。
(3)如果一个节点左孩子为空右孩子不为空,该树不符合完全二叉树的特点,返回false。
(4)如果一个节点左孩子不为空且右孩子为空,或者左右孩子均为空,如果该节点之后的队列中所有的节点均为叶子节点,该树则为完全二叉树。
代码实现:
struct Node
{
int _data;
Node* _left;
Node* _right;
Node(int x)
:_data(x)
,_left(NULL)
,_right(NULL)
{}
};
//创建二叉树
class Binarytree
{
public:
Binarytree(const int a[],int size,int invalide)
{
int index = 0;
_root = CreateBinarytree(a,size,index,invalide);
}
Node* CreateBinarytree(const int a[],int size,int &index,int invalide)
{
Node* root = NULL;
if(index < size && a[index] !=invalide)
{
root = new Node(a[index]);
root ->_left = CreateBinarytree(a,size,++index,invalide);
root ->_left = CreateBinarytree(a,size,++index,invalide);
}
return root;
}
//判断是否是完全二叉树
bool IsComplateBinarytree()
{
if(_root == NULL)
{
return false;
}
queue<Node*>q;
q.push(_root);
while(!q.empty())
{
Node* cur = q.front();
//1.左右孩子均不为空
if(cur->_left&&cur->_right)
{
q.pop();
q.push(cur->_left);
q.push(cur->_right);
}
//2.左孩子为空且右孩子不为空
if(cur->_left == NULL && cur->_right)
{
return false;
}
//3.左孩子不为空且右孩子为空,或者左右孩子均为空
if((cur->_left && cur->_right == NULL) || (cur->_left == NULL)&&(cur->_right == NULL))
{
if(cur->_left && cur->_right == NULL)
{
q.push(cur->_left);
}
q.pop();
while(!q.empty())
{
cur = q.front();
if((cur->_left == NULL)&&(cur->_right == NULL))
{
q.pop();
}
else
{
return false;
}
}
return true;
}
}
return true;
}
private:
Node* _root;
};
int main()
{
int a1[]={1,2,'#',3,'#','#',4,5,'#',6,'#',7,'#','#',8}; //0
//int a2[]={1,2,3,'#','#',4,'#','#',5,6}; //1
Binarytree tr(a1,20,'#');
cout<<tr.IsComplateBinarytree()<<endl;
return 0;
}