對應的專業英語詞彙
單詞 | 意思 |
---|---|
even number | 偶數 |
positive | 正數 |
postorder traversal | 後序遍歷 |
inorder traversal | 中序遍歷 |
level order traversal | 層序遍歷 |
invert | 反轉 |
二叉樹知識點
-
二叉樹的性質:root的索引爲index時,
它的對應左子節點爲index2, 右子節點爲 index2+1 -
二叉查找樹的中序遍歷是一個遞增的序列
-
已知兩個序列,求另一個(兩個步驟)
- 用一個序列中
root
的值尋找另一個序列的位置 - 通過該位置,將左右的
start
和end
進行更新
二叉樹三種遍歷之間轉換:
分爲三步驟=-=
- 邊界條件進行返回
- 通過後序和先序的root尋找中序中root的位置
- 通過遞歸調用函數(核心點)
當start和end相等時:也與root相等,此時i尋找到的即爲本身,左右子樹的遞歸達到邊界,也可將此值存入
- 根據後序中序建樹時,模板代碼爲:
root
爲值,start
和end
爲中序遍歷中的索引。
不能通過左子樹求對應右子樹的根,因爲後序中的起始點不確定。
void pre(int root, int start, int end) {
//當找到葉子節點時將返回;
if(start > end) return ;
int i = start;
//尋找後序中root索引對應的中序位置,設爲i
while(i < end && in[i] != post[root]) i++;
//先序遍歷的性質決定。
pre.push_back(post[root]);
//遍歷左右的子樹,start和end根據中序遍歷給出,
//子樹的root點主要根據後序遍歷中的位置給出,
//右子樹的根節點爲父親root的前一個,
//左子樹的根節點爲:父親root-右子樹個數的前一個,即(root-(end-(i+1)+1)-1)
pre(root-end+i-1, start, i - 1);
pre(root - 1, i + 1, end);
//root索引根據後序遍歷的性質進行更新
}
- 根據先序中序遍歷建樹:
void postorder(int root, int start, int end) {
if (start > end) return;
int i = start;
while (i < end && in[i] != pre[root]) i++;
postorder(root + 1, start, i - 1);
postorder(root + i - start + 1, i + 1, end);
//後序遍歷的性質決定
post.push_back(pre[root]);
}
- 根據先序和後序遍歷,給出中序並判斷是否唯一
void inorder(int start,int end,int root)
{
if(start>end) return;
int i=0;
while(i<n&&post[end-1]!=pre[i]) i++;
if(pre[root+1]==pre[i]) flag=true;
inorder(start,start+i-root-2,root+1);
in.push_back(pre[root]);
inorder(start+i-root-1,end-1,i);
return;
}
二叉搜索樹
中序遍歷一棵二叉搜索樹得到的序列爲從小到大的序列
struct node
{
int v;
node *l,*r;
vector<int> v1;
};
node* build(node *root,int v)
{
if(root==NULL)
{
root=new node();
root->v=t1;
root->l=root->r=NULL;
}
else if(root->v<t1)
root->l=build(root->l,v);
else root->r=build(root->r,v);
return root;
}
int main()
{
scanf("%d %d\n", &n1, &n2);
node *root=NULL;
for(int i=0;i<n2;i++)
{
scanf("%d",&t1);
root=build(root,t1);
}
return 0;
}
AVL平衡二叉樹
介紹性概念:【鏈接】
代碼實現講解較好【鏈接】
模板及樣例:
類似於管理一個指針:
1.指針傳遞:指針傳遞其實是值傳遞的一種,它傳遞的是地址。值傳遞過程中,被調函數的形參作爲被調函數的局部變量來處理改變函數形參並不影響函數外部的實參,即在函數的棧中有開闢了內存空間來存放主調函數放進來實參的值。
#include <iostream>
using namespace std;
struct node {
int val;
struct node *left, *right;
};
//這裏*指返回一個指針。爲了同main函數裏的root指針類型相同
node *rotateLeft(node *root) {
node *t = root->right;
root->right = t->left;
t->left = root;
return t;
}
node *rotateRight(node *root) {
node *t = root->left;
root->left = t->right;
t->right = root;
return t;
}
node *rotateLeftRight(node *root) {
root->left = rotateLeft(root->left);
return rotateRight(root);
}
node *rotateRightLeft(node *root) {
root->right = rotateRight(root->right);
return rotateLeft(root);
}
int getHeight(node *root) {
if(root == NULL) return 0;
return max(getHeight(root->left), getHeight(root->right)) + 1;
}
node *insert(node *root, int val) {
if(root == NULL) {
root = new node();
root->val = val;
root->left = root->right = NULL;
} else if(val < root->val) {
root->left = insert(root->left, val);
if(getHeight(root->left) - getHeight(root->right) == 2)
root = val < root->left->val ? rotateRight(root) : rotateLeftRight(root);
} else {
root->right = insert(root->right, val);
if(getHeight(root->left) - getHeight(root->right) == -2)
root = val > root->right->val ? rotateLeft(root) : rotateRightLeft(root);
}
return root;
}
int main() {
int n, val;
scanf("%d", &n);
node *root = NULL;
for(int i = 0; i < n; i++) {
scanf("%d", &val);
root = insert(root, val);
}
printf("%d", root->val);
return 0;
}
如果把代碼改成引用形式,也能成立,並且看起來更易讀懂
2.引用傳遞:被調函數的形參雖然也作爲局部變量在棧中開闢了內存空間,但在棧中放的是由主調函數放進來的實參變量的地址。被調函數對形參的任何操作都被間接尋址,形參在任意改動都直接影響到實參。
struct node
{
int val;
node *left,*right;
};
int getheight(node *&root)
{
if(root==NULL)
return 0;
else
return max(getheight(root->left),getheight(root->right))+1;
}
void rotateLeft(node *&root)
{
node *t=root->right;
root->right=t->left;
t->left=root;
root=t;
}
void rotateRight(node *&root)
{
node *t=root->left;
root->left=t->right;
t->right=root;
root=t;
//cout<<"R"<<endl;
}
void RL(node *&root)
{
rotateRight(root->right);
rotateLeft(root);
//cout<<"RL"<<endl;
}
void LR(node *&root)
{
rotateLeft(root->left);
rotateRight(root);
}
void insert1(int t,node *&root)
{
if(root==NULL)
{
root=new node();
root->left=root->right=NULL;
root->val=t;
//cout<<"666";
}
else
{
if(t<root->val)
{
insert1(t,root->left);
if(getheight(root->right)-getheight(root->left)==-2)
{
if(getheight(root->left->left)-getheight(root->left->right)==1)
rotateRight(root);
else if(getheight(root->left->left)-getheight(root->left->right)==-1)
LR(root);
}
}
else
{
insert1(t,root->right);
if(getheight(root->right)-getheight(root->left)==2)
{
if(getheight(root->right->left)-getheight(root->right->right)==-1)
rotateLeft(root);
else if(getheight(root->right->left)-getheight(root->right->right)==1)
RL(root);
}
//cout<<"666";
}
}
}
int main()
{
int n,t;
scanf("%d", &n);
node * root=NULL;
for(int i=0;i<n;i++)
{
cin>>t;
insert1(t,root);
//cout<<root->val;
}
PAT甲級題目舉例:
中序,後序,先序遍歷之間的互相求解
1020 Tree Traversals (25分)
幾個注意點:
- 若左右子樹爲空,直接返回未壓入新節點,相當於層序遍歷結點容器中對應的序號空了出來,不影響後面按序號排序的順序
- sort()函數可以對vector進行排序,但排序時需要給cmp比較函數
- vector類型,首地址並不能使用:a 這種寫法。a.begin()被用來給出對應首地址,a.end()被用來給出對應結束的地址。(在fill()填充函數和sort()排序函數中進行了對應實驗。)
- 傳入的根節點需要爲1,不然index*2會一直爲0
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<vector>
using namespace std;
struct node
{
int index,value;
};
int post[50],in[50];
vector<node> level;
bool cmp(node d1, node d2)
{
return d1.index<d2.index;
}
//對應的層序求解
void lev(int start, int end ,int root, int index)
{
if(start>end) return;
level.push_back({index,post[root]});
int i=start;
while(i<=end && post[root]!=in[i])
i++;
lev(start,i-1,root-end-1+i,2*index);
lev(i+1,end, root-1, 2*index+1);
}
int main()
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&post[i]);
for(int i=0;i<n;i++)
scanf("%d",&in[i]);
lev(0,n-1,n-1,1);
//對索引進行排序,就算有缺失,也能進行很好的排序並不影響結果。
sort(level.begin(),level.end(),cmp);
printf("%d",level[0].value);
for(int j=1;j<level.size();j++)
printf(" %d", level[j].value);
return 0;
}
1086 Tree Traversals Again (25分)
- 這道題有個很有意思的點,就是壓入棧的節點按先序遍歷的順序…(????結果還真的是,之前根本想不到啊)
#include<algorithm>
#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
using namespace std;
int number,n;
vector<int> pos,pre,ino;
void dfs(int start, int end1, int root)
{
//root 非值,爲先序索引,end,start爲中序索引
if(start>end1)
return;
int index=start;
while(pre[root]!=ino[index]&& index<end1) index++;
dfs(start, index-1, root+1);
dfs(index+1,end1, root+index+1-start);
pos.push_back(pre[root]);
}
int main()
{
scanf("%d", &n);
char op[6];
vector<int> s;
for(int i=0;i<2*n;i++)
{
scanf("%s",&op);
if(strlen(op)==4)
{
scanf("%d", &number);
pre.push_back(number);
s.push_back(number);
//printf("push\n");
}
else
{
ino.push_back(s[s.size()-1]);
//printf("pop %d\n ",pre[pre.size()-1]);
s.pop_back();
}
}
dfs(0, n-1, 0);
for(int i=0;i<pos.size()-1;i++)
printf("%d ", pos[i]);
printf("%d",pos[pos.size()-1]);
return 0;
}