前言
看了Acwing老师的一些课
**补充知识:访问vector最后一个元素用end() -1
而不是end();-------待补充。
** 完全二叉树的存储技巧,用数组,左孩子一定是2x,右孩子一定是2x+1
完全二叉树达到空结点的标志是当前结点root编号大于结点个数n 。
一.二叉查找树
1.1二叉查找树定义
二叉查找树有很多名字,还有排序二叉树,二叉搜索树等。
其定义如下:
①要么是空树。
②要么其左右子树都是二叉查找树,且左子树所有节点都小于等于根节点,右子树所有节点都大于等于根节点。
1.2二叉查找树上的操作
1.查找,遍历树
void search (node* root, int x )
{
if(root == NULL)
return ;
if(x == root->data)
cout<<"ok";
else if(x < root->data)
search(root->lchild,x);
else
search(root->rchild);
}
2.插入操作
同样是遍历的思路
void insert( node* &root ,int x )
{
if(root ==NULL)
{
root = newNode(x);
return; // return很重要!一定要设置出口
}
if(x == root->data)
return ;
else if (x <= root ->data)
insert(root->lchild,x);
else
insert(root ->rchild,x);
}
3.二叉查找树的建立
注意:同一组数据,输入顺序不同,建立的二叉查找树也不同
node* Create(int data[],int n)
{
node* root = NULL;
for(int i=0;i<n;i++)
insert(root,data[i]);
return root;
}
4.二叉查找树的删除
如图1,若删除根节点,可以考虑用比根小的最大结点4覆盖(后继),也可以考虑用比根大的最小结点6覆盖(前驱),首先建立find函数找到他们。
node* findMax(node* root)
{
while(root->rchild !=NULL)
root = root->rchild;
return root;
{
node* findMin(node* root)
{
while(root->lchild != NULL)
root = root->lchild;
return root;
}
void deleteNode(node* &root ,int x)
{
if(root == NULL) return ;
if(root->data == x)
{
if(root->lchild == NULL && root->rchild == NULL)
root = NULL ;
else if (root-> lchild != NULL )
{
node* pre = findMax(root->lchild);
root->data = pre->data;
deleteNode(root->lchild,pre->data);
}
else
{
node* next = findMin(root->rchild);
root->data = next ->data;
deleteNode(root->rchild,next->data);
}
else if (root->data < x)
delete(root->rchild,x);
else if(root->data > x )
delete(root->lchild,x);
}
1.3二叉查找树的性质
**对BTS进行中序遍历,结果是有序的!**
二.平衡二叉树
2.1 AVL树的定义
1.AVL仍然是一棵BST树,只是链式的BST树复杂度达到了O(n),只是增加了“平衡”
的要求:任意结点左子树和右子树高度差绝对值不超过1.
每个结点都有一个平衡因子,表示左子树高度减去右子树高度。
只要保证每个节点平衡因子不大于1,就能O(logn)级别。
struct node
{
int v; //权值
int height; //当前子树高度
node* lchild, rchild;
}
新建结点
node* newNode(int v)
{
node* Node = new node;
Node->v = v;
Node->height = 1 ;
Node->lchild = Node->rchild = NULL;
return Node;
}
更新height
void updateHeight(node* root)
{
root->height = max(getHeight(root->lchild),getHeight(root->rchild));
}
int getHeiht(node* root)
{
if(root==NULL)
return 0;
return root->height;
}
计算结点平衡因子
int getbalanceFactor(node* root)
{
return getHeight(root->lchild)-getHeight(root-rchild);
}
2.2平衡二叉树的操作
1.查找操作,时间复杂度O(logn)
与上面BST查找方式一致。
2.插入操作
先定义左旋操作:假如要BST中的A结点和B结点互换,且交换之后仍是二叉查找树。
左旋步骤如下:
①让B的左子树成为A的右子树。
②让A成为B的右子树。
最后把根节点设置为B.
心中有图,需要记忆
void L(node* &root)
{
node* temp = root->rchild; //temp就是B
root->rchild = temp->lchild;
temp-lchild = root ;
updateHeight(root);
updateHeight(temp);
root = temp;
}
右旋:
①让A的右子树成为B的左子树。
②让B成为A的右子树。
最后把根节点设置为B.
记忆,心中有图
void R(node* &root)
{
node* temp = root->lchild;
root->lchild = temp->rchild;
temp->rchild = root;
update(root);
update(temp);
root = temp ;
}
现在考虑AVL树上插入节点之后失衡的情况。
共四种情况。
void insert(node* &root,int v)
{
if(root == NULL)
{
root = newNode(v);
return ;
}
if(v<root->v)
{
insert(root->lchild,v);
updateHeight(root);
if(getBalanceFactor(root)==2)
{
if(getBalanceFactor(root->lchild)==1)
R(root);
else if(getBalanceFactor(root->lchild)==-1)
{
L(root->lchild);
R(root);
}
}
}
else
{
insert(root->rchild,v);
updateHeight(root);
if(getBalanceFactor(root)==-2)
{
if(getBalanceFactor(root->rchild)==-1)
L(root);
else if(getBalanceFactor(root->rchild)==--1)
{
R(root->rchild);
L(root);
}
}
}
2.3 AVL树的建立
node* Create(int data[],int n)
{
node* root = NULL;
for(int i=0;i<n;i++)
insert(root,data[i]);
return root;
}
三.哈夫曼树
3.1哈夫曼树定义和实现
先看这么一个问题:合并果子
题意:有好几堆果子,要合并成一堆,每一次合并,多多可以把两堆果子合并到一起,
消耗的体力等于两堆果子的重量之和。所有的果子经过n-1次合并之后,就只剩下一堆了。
多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。
求合成一堆消耗的最小体力。
哈夫曼树是采用了贪心的思想,每次那最小的两堆。
已知n个数,寻找一棵树,使得树的所有叶子节点的权值恰好为这n个数,并且使得这棵树
的带权路径长度最小。
#include <iostream>
#include <queue>
using namespace std;
priority_queue<int ,vector<int>,greater<int>> q;
int main()
{
int n;
int temp ,x,y;
int ans = 0;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>temp;
q.push(temp);
}
while(q.size()>1)
{
x = q.top();
ans = ans + x;
q.pop();
y = q.top();
q.pop();
ans = ans + y ;
y = y + x;
q.push(y);
}
cout<<ans;
return 0;
}
四.练习
1.题目链接:UVA1525 Falling leaves
#include <iostream>
#include <cstring>
using namespace std;
struct node
{
char data;
node* lchild;
node* rchild;
};
node* newNode(char c)
{
node* Node = new node;
Node->data = c;
Node->lchild = Node->rchild = NULL;
return Node;
}
void insert(node* &root,char c)
{
if(root == NULL)
{
root = newNode(c);
return ;
}
if(c < root->data)
insert(root->lchild,c);
else if(c > root->data)
insert(root->rchild,c);
}
void preorder(node* root)
{
if(root == NULL)
return;
cout<<root->data;
preorder(root->lchild);
preorder(root->rchild);
}
int main()
{
string s1;
while(1)
{
string s = "";
while(cin>>s1&&s1[0]!='*'&&s1[0]!='$')
s = s + s1;
node* root = NULL;
for(int i =s.size()-1;i>=0;i--)
insert(root,s[i]);
preorder(root);
cout<<endl;
if(s1[0]=='$')
break;
}
return 0;
}
PTA1043 Is It a Binary Search Tree (25 分)
#include <iostream>
#include <vector>
using namespace std;
const int maxn = 1010;
int temp[maxn];
struct node
{
int data;
node* lchild;
node* rchild;
}Node[maxn];
node* root = NULL;
vector<int> origin,pre,post,preM,postM;
node* newNode(int x)
{
node* root = new node;
root->data = x;
root->lchild = NULL;
root->rchild = NULL;
return root;
}
void insert(node* &root,int x)
{
if(root==NULL)
{
root = newNode(x);
return;
}
if(x<root->data)
insert(root->lchild,x);
else if(x>=root->data)
insert(root->rchild,x);
}
void preorder(node* root,vector<int>& vi)
{
if(root == NULL)
return ;
vi.push_back(root->data);
preorder(root->lchild,vi);
preorder(root->rchild,vi);
}
void postorder(node* root,vector<int>& vi)
{
if(root == NULL)
return;
postorder(root->lchild,vi);
postorder(root->rchild,vi);
vi.push_back(root->data);
}
void premirro(node* root,vector<int>& vi)
{
if(root==NULL)
return;
vi.push_back(root->data);
premirro(root->rchild,vi);
premirro(root->lchild,vi);
}
void postmirro(node* root,vector<int>& vi)
{
if(root==NULL)
return;
postmirro(root->rchild,vi);
postmirro(root->lchild,vi);
vi.push_back(root->data);
}
int main()
{
int n;
cin>>n;
for(int i=0;i<n;i++)
{
cin>>temp[i];
origin.push_back(temp[i]);
insert(root,temp[i]);
}
preorder(root,pre);
postorder(root,post);
premirro(root,preM);
postmirro(root,postM);
if(pre==origin)
{
cout<<"YES"<<endl;
for(int i=0;i<post.size()-1;i++)
cout<<post[i]<<' ';
int t = post.size()-1;
cout<<post[t];
}
else if(preM==origin)
{
cout<<"YES"<<endl;
for(int i=0;i<postM.size()-1;i++)
cout<<postM[i]<<' ';
int t = postM.size()-1;
cout<<postM[t];
}
else
cout<<"NO";
return 0;
}
1064 Complete Binary Search Tree (30 分)
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 1010;
int BST[maxn];
int num[maxn];
int n;
int index = 0;
void inorder(int root)
{
if(root>n) return ;
inorder(root*2);
BST[root] = num[index++];
inorder(root*2+1);
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
cin>>num[i];
sort(num,num+n);
inorder(1);
for(int i=1;i<n;i++)
cout<<BST[i]<<' ';
cout<<BST[n];
return 0;
}
1099 Build A Binary Search Tree (30 分)
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
const int maxn = 110;
int tem[maxn];
int cnt = 0;
int cnt2 = 0;
int n;
struct node
{
int data;
int lchild;
int rchild;
}Node[maxn];
void inorder(int root)
{
if(root == -1)
return;
inorder(Node[root].lchild);
Node[root].data = tem[cnt++];
inorder(Node[root].rchild);
}
void BFS(int root)
{
queue<int> q;
q.push(root);
while(!q.empty())
{
int t = q.front();
cout<<Node[t].data;
cnt2++;
if(cnt2!=n)
cout<<' ';
q.pop();
if(Node[t].lchild != -1) q.push(Node[t].lchild);
if(Node[t].rchild != -1) q.push(Node[t].rchild);
}
}
int main()
{
cin>>n;
for(int i=0;i<n;i++)
{
cin>>Node[i].lchild>>Node[i].rchild;
}
for(int i=0;i<n;i++)
cin>>tem[i];
sort(tem,tem+n);
inorder(0);
BFS(0);
return 0;
}