最常用代码:
一:造树
依据前序,中序,造树:
const int N=2e5+5;
int n;
int pre[N];
int ind[N];
struct node{
int val;
node *l,*r;
};
node *mktree(int h1,int h2,int len){
if(len==0) return nullptr;
node *rt=new node;//要初始化 将l,r默认为null
int t =pre[h1];
rt->val=t;
int i;
for(i=h2;i<h2+len;i++) if(ind[i]==t) break;
int l1=i-h2;
int l2=len-1-l1;
rt->l=mktree(h1+1,h2,l1);
rt->r=mktree(h1+l1+1,i+1,l2);
return rt;
}
cin>>n;
fori(i,1,n) cin>>pre[i];
fori(i,1,n) cin>>ind[i];
node *rt = mktree(1,1,n);
依据后序,中序,造树:
const int N=2e5+5;
int n;
int pos[N];
int ind[N];
vector<int> ans;
struct node{
int val;
node *l;
node *r;
};
node *mktree(int h1,int h2,int len){
if(len==0) return nullptr;
node *rt =new node;
int t=pos[h2+len-1];
rt->val=t;
int i;
for(i=h1;i<h1+len;i++) if(ind[i]==t) break;
int l1=i-h1;
int l2=len-1-l1;
rt->l=mktree(h1,h2,l1);
rt->r=mktree(i+1,h2+l1,l2);
return rt;
}
cin>>n;
fori(i,1,n) cin>>ind[i];
fori(i,1,n) cin>>pos[i];
node *rt = mktree(1,1,n);
依据前序,后序,猜测树:
const int N=2e2+5;
int n;
int pre[N];
int pos[N];
struct node{
int val;
node *l=NULL;
node *r=NULL;
};
node *mktree(int h1,int h2,int len){
if(len==0) return NULL;
node *rt= new node;
rt->val = pre[h1];
if(len==1) return rt;
int t=pre[h1+1];
int i;
for(i=h2;i<len+h2;i++) if(pos[i]==t) break;
int l1=i-h2+1;
int l2=len-1-l1;
if(l2==0) can=false;
rt->l= mktree(h1+1,h2,l1);
rt->r=mktree(h1+1+l1,i+1,l2);
return rt;
}
cin>>n;
for(int i=1;i<=n;i++) cin>>pre[i];
for(int i=1;i<=n;i++) cin>>pos[i];
node *rt=mktree(1,1,n);
依据前序,二叉搜索树,构造树:
const int N=2e5+5;
int m,n;
int pre[N];
struct node{
int val;
node *l,*r;
};
unordered_map<int,node*> mp;
node *mktree(int h,int t){
if(h>t) return nullptr;
node *rt = new node;
int t1=pre[h];
rt->val=t1;
int i;
for(i=h+1;i<=t;i++) if(pre[i]>=t1) break;
rt->l=mktree(h+1,i-1);
rt->r=mktree(i,t);
return rt;
}
cin.tie(0);
ios::sync_with_stdio(false);
cin>>m>>n;
fori(i,1,n) cin>>pre[i];
node *rt=mktree(1,n);
二:遍历方式
vector v//存数据:
树用结构体+指针构造好了后,就可以任意遍历了
前序遍历:
void preorder(node *rt){
if(rt){
v.push_back(rt->val);
preorder(rt->l);
preorder(rt->r);
}
}
中序遍历:
void inorder(node *rt){
if(rt){
preorder(rt->l);
v.push_back(rt->val);
preorder(rt->r);
}
}
后序遍历
void postorder(node *rt){
if(rt){
postorder(rt->l);
postorder(rt->r);
v.push_back(rt->val);
}
}
层次遍历
void levelorder(node *rt){
queue<node*> q;
q.push(rt);
while(q.size()){
auto t=q.front();q.pop();
v.push_back(t->val);
if(t->l) q.push(t->l);
if(t->r) q.push(t->r);
}
}
树,有二叉树,非二叉树。
将数组建成二叉树。
更详细的:https://blog.youkuaiyun.com/qq_21989927/article/details/108197861
数组从0开始,
找子节点,为2i+1,2i+2;
找父节点,为(i-1)/2
依据层次遍历,二叉搜索树,构造树:
#include<bits/stdc++.h>
using namespace std;
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) {}
};
vector<int> arr;
void creTree(TreeNode* &rt,int idx) {
if(idx>arr.size()-1) return;
rt = new TreeNode(arr[idx],nullptr,nullptr);
if(idx*2+1<=arr.size()-1) creTree(rt->left,idx*2+1);
if(idx*2+2<=arr.size()-1) creTree(rt->right,idx*2+2);
}
void levOrd(TreeNode* rt) {
vector<int> levVal;
queue<TreeNode*> q;
q.push(rt);
while(q.size()) {
auto t = q.front();q.pop();
levVal.push_back(t->val);
if(t->left) q.push(t->left);
if(t->right) q.push(t->right);
}
cout<<"层次遍历:";
for(int i:levVal) cout<<i<<" ";
cout<<endl;
}
int main() {
int t;
// 1 8 10 3 5 7
while(cin>>t) {
arr.push_back(t);
if(cin.get()=='\n') break;
}
sort(arr.begin(),arr.end());
TreeNode* rt = new TreeNode();
creTree(rt,0);
levOrd(rt);
return 0;
}
二叉树遍历
先序中序后序。
分别为,根左右,左根右,左右根。
前,中,后,层次遍历代码实现
static int a[]= {2,3,1,2,3,23,2};//就是层次遍历
public static void main(String[] args) {
// TODO Auto-generated method stub
priorder(0);
System.out.println();
midorder(0);
System.err.println();
reaorder(0);
}
public static void priorder(int x)
{
if(x<0||x>=a.length) return;
System.out.print(a[x]+" ");//根
priorder(x*2+1);//左
priorder(x*2+2);//右
}
public static void midorder(int x)
{
if(x<0||x>=a.length) return;
midorder(x*2+1);//左
System.out.print(a[x]+" ");//根
midorder(x*2+2);//右
}
public static void reaorder(int x)
{
if(x<0||x>=a.length) return;
reaorder(x*2+1);//左
reaorder(x*2+2);//右
System.out.print(a[x]+" ");//根
}
void levorder(int rt)//层次遍历 当用结构体存树时
{
vector<int>ve;
queue<int>q;
q.push(rt);
while(!q.empty()){
int m = q.front();
q.pop();
ve.push_back(m);
if(a[m].l != 0)q.push(a[m].l);
if(a[m].r != 0)q.push(a[m].r);
}
int len = ve.size();
for(int i = 0; i < len-1; i++){
cout << ve[i] << " ";
}
cout << ve[len-1] << endl;
}
二叉树遍历之间的相互转换
1.已知后序遍历和中序遍历求出层序遍历。
L2-006 树的遍历 (25 分)
给定一棵二叉树的后序遍历和中序遍历,请你输出其层序遍历的序列。这里假设键值都是互不相等的正整数。
输入格式:
输入第一行给出一个正整数N(≤30),是二叉树中结点的个数。第二行给出其后序遍历序列。第三行给出其中序遍历序列。数字间以空格分隔。
输出格式:
在一行中输出该树的层序遍历的序列。数字间以1个空格分隔,行首尾不得有多余空格。
输入样例:
7
2 3 1 5 7 6 4
1 2 3 4 5 6 7
输出样例:
4 1 6 3 5 7 2
这个题就是先用结构体构建左子树和右子树,然后使用bfs(vector,queue)输出层序遍历;
方法一:结构体只存整型l,r,指向数据。
int n;
struct node{
int l, r;
}a[maxn];
int ba[maxn], mid[maxn];
int creatTree(int la, int ra, int lb, int rb){
if(la > ra)return 0;
int t = ba[ra], q;
q = lb;
while(mid[q] != t)q++;
int q1 = q - lb;
a[t].l = creatTree(la, la+q1-1, lb, q-1);
a[t].r = creatTree(la+q1, ra-1, q+1, rb);
return t;
}
void bfs(int rt){
vector<int>ve;
queue<int>q;
q.push(rt);
while(!q.empty()){
int m = q.front();
q.pop();
ve.push_back(m);
if(a[m].l != 0)q.push(a[m].l);
if(a[m].r != 0)q.push(a[m].r);
}
int len = ve.size();
for(int i = 0; i < len-1; i++){
cout << ve[i] << " ";
}
cout << ve[len-1] << endl;
}
int main(){
ios::sync_with_stdio(false);
cin >> n;
for(int i = 0; i < n; i++)cin >> ba[i];
for(int i = 0; i < n; i++)cin >> mid[i];
int t = ba[n-1];
creatTree(0, n-1, 0, n-1);
bfs(t);
return 0;
}
方法二:结构体存 int val,int l,r 。
int n;
const int maxx=3e3;
struct node{
int val;
int l, r;
}a[maxx];
int ba[maxx], mid[maxx];
int creatTree(int la, int ra, int lb, int rb){
if(la > ra)return 0;
int t = ba[ra], q;
a[t].val= t;
q = lb;
while(mid[q] != t)q++;
int q1 = q - lb;
a[t].l = creatTree(la, la+q1-1, lb, q-1);
a[t].r = creatTree(la+q1, ra-1, q+1, rb);
return t;
}
void bfs(int rt){
vector<int>ve;
queue<int>q;
q.push(rt);
while(!q.empty()){
int m = q.front();
q.pop();
ve.push_back(a[m].val);
if(a[m].l != 0)q.push(a[m].l);
if(a[m].r != 0)q.push(a[m].r);
}
int len = ve.size();
for(int i = 0; i < len-1; i++){
cout << ve[i] << " ";
}
cout << ve[len-1] << endl;
}
int main(){
ios::sync_with_stdio(false);
cin >> n;
for(int i = 0; i < n; i++)cin >> ba[i];
for(int i = 0; i < n; i++)cin >> mid[i];
int t = ba[n-1];
creatTree(0, n-1, 0, n-1);
bfs(t);
return 0;
}
方法三:结构体存 int val,node *l,*r 指向一个节点。
const int N=2e2+5;
int n,post[N],in[N];
struct node{
int val;
node* lef;
node* rig;
}tr[N];
node* make(int h1,int t1,int h2,int t2){
if(h1>t1) return NULL;
node* p=new node;
p->val=post[t1];
int idx=h2;
for(;in[idx]!=post[t1];idx++);
p->lef=make(h1,idx-1-h2+h1,h2,idx-1);
p->rig=make(idx-t2+t1,t1-1,idx+1,t2);
return p;
}
int main()
{
cin.tie(0);
ios::sync_with_stdio(false);
cin>>n;
fori(i,1,n) cin>>post[i];
fori(i,1,n) cin>>in[i];
node* root= make(1,n,1,n);
node* q[N];
int h=0,t=-1;
q[++t]=root;
while(h<=t){
if(h) cout<<" ";
node* tem=q[h++];
cout<<tem->val;
if(tem->lef) q[++t]=tem->lef;
if(tem->rig) q[++t]=tem->rig;
}
return 0;
}
三种方法总结:
1, 结构体 l,r 指向数据 (没有节点信息)
2,结构体 val,l,r 指向一个节点 (有节点信息,也有数据信息) 空可以为 0,-1等数据
3, 结构体 val,node *l,*r 指向一个节点(有节点信息,也有数据信息) 空只能为NULL,但是构造树时,更灵活,方法可以有也可以无返回值
所以推荐用方法3!!!! 更清晰明了
2.已知先序和中序求出后序:
#include<bits/stdc++.h>
#define fori(i,s,e) for(int i=s;i<=e;i++)
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> PII;
const int N=2e5+5;
int n;
int pre[N];
int ind[N];
struct node{
int val;
node *l,*r;
};
node *mktree(int h1,int h2,int len){
if(len==0) return nullptr;
node *rt=new node;
int t =pre[h1];
rt->val=t;
int i;
for(i=h2;i<h2+len;i++) if(ind[i]==t) break;
int l1=i-h2;
int l2=len-1-l1;
rt->l=mktree(h1+1,h2,l1);
rt->r=mktree(h1+l1+1,i+1,l2);
return rt;
}
vector<int> a;
void postorder(node *rt){
if(rt){
postorder(rt->l);
postorder(rt->r);
a.push_back(rt->val);
}
}
int main()
{
cin.tie(0);
ios::sync_with_stdio(false);
cin>>n;
fori(i,1,n) cin>>pre[i];
fori(i,1,n) cin>>ind[i];
node *rt = mktree(1,1,n);
postorder(rt);
cout<<a[0];
return 0;
}
string s1, s2;
void creatTree(int la, int ra, int lb, int rb){
int q = lb;
if(la > ra)return ;
while(s2[q] != s1[la]) q++;
int q1 = q - lb;
creatTree(la+1, la+q1, lb, q-1);
creatTree(la+q1+1, ra, q+1, rb);
cout << s1[la];
}
int main(){
ios::sync_with_stdio(false);
cin >> s1 >> s2;
cout << s1 <<" " << s2 << endl;
creatTree(0, s1.length()-1, 0, s2.length()-1);
return 0;
}
3.已知中序和后序求出先序:
根据中序和后序,构造树:
#include<bits/stdc++.h>
#define fori(i,s,e) for(int i=s;i<=e;i++)
#define x first
#define y second
using namespace std;
typedef long long ll;
typedef long double ld;
typedef pair<int,int> PII;
const int N=2e5+5;
int n;
int pos[N];
int ind[N];
vector<int> ans;
struct node{
int val;
node *l=NULL;
node *r=NULL;
};
node *mktree(int h1,int h2,int len){
if(len==0) return nullptr;
node *rt =new node;
int t=pos[h2+len-1];
rt->val=t;
int i;
for(i=h1;i<h1+len;i++) if(ind[i]==t) break;
int l1=i-h1;
int l2=len-1-l1;
rt->l=mktree(h1,h2,l1);
rt->r=mktree(i+1,h2+l1,l2);
return rt;
}
void zigzagging (node *root){
queue<node*> q;
q.push(root);
int level=0;
while(int cnt=q.size()){//q.size()为0 退出
level++;
vector<int> temp;
while(cnt--){
auto t=q.front();q.pop();
temp.push_back(t->val);
if(t->l) q.push(t->l);
if(t->r) q.push(t->r);
}
if(level&1) for(int i=temp.size()-1;i>=0;i--) ans.push_back(temp[i]);
else for(int i=0;i<temp.size();i++) ans.push_back(temp[i]);
}
}
int main()
{
cin.tie(0);
ios::sync_with_stdio(false);
cin>>n;
fori(i,1,n) cin>>ind[i];
fori(i,1,n) cin>>pos[i];
node *rt = mktree(1,1,n);
zigzagging(rt);
for(int i=0;i<ans.size();i++){
if(i) cout<<" ";
cout<<ans[i];
}
return 0;
}
void creatTree(int la, int ra, int lb, int rb){
int q = la;
if(la > ra) return ;
while(s1[q] != s2[rb])q++;
int q1 = q - la;
cout << s2[rb];
creatTree(la, q-1, lb, lb+q1-1);
creatTree(q+1, ra, lb+q1, rb-1);
}
int main(){
ios::sync_with_stdio(false);
cin >> s1 >> s2;
cout << s1 <<" " << s2 << endl;
creatTree(0, s1.length()-1, 0, s2.length()-1);
return 0;
}
4.知道先序和后序是无法确定一颗二叉树的,因为无法确定左子树和右子树-》猜测树结构:
输出对应的中序遍历:
方法一:无返回值
#include<bits/stdc++.h>
using namespace std;
const int N=2e2+5;
bool can=true;
int n;
int pre[N];
int pos[N];
vector<int> v;
struct node{
int val;
node *l=NULL;
node *r=NULL;
};
void mktree(node*&rt,int h1,int h2,int len){ //构造树
if(len==0) return ;
rt= new node;
rt->val = pre[h1];
if(len==1) return ;
int t=pre[h1+1];
int i;
for(i=h2;i<len+h2;i++) if(pos[i]==t) break;
int l1=i-h2+1;
int l2=len-1-l1;//只能是 l2判0
if(l2==0) can=false;
mktree(rt->l,h1+1,h2,l1);
mktree(rt->r,h1+1+l1,i+1,l2);
}
void inorder(node *rt){//中序,树已经成型,可以随时换遍历方式
if(rt){
inorder(rt->l);
v.push_back(rt->val);
inorder(rt->r);
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>pre[i];
for(int i=1;i<=n;i++) cin>>pos[i];
node *rt=NULL;
mktree(rt,1,1,n);
if(can) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
inorder(rt);
for(int i=0;i<v.size();i++){
if(i) cout<<' ';
cout<<v[i];
}
cout<<endl;
return 0;
}
方法二:有返回值:
#include<bits/stdc++.h>
using namespace std;
const int N=2e2+5;
bool can=true;
int n;
int pre[N];
int pos[N];
vector<int> v;
struct node{
int val;
node *l=NULL;
node *r=NULL;
};
node *mktree(int h1,int h2,int len){
if(len==0) return NULL;
node *rt= new node;
rt->val = pre[h1];
if(len==1) return rt;
int t=pre[h1+1];
int i;
for(i=h2;i<len+h2;i++) if(pos[i]==t) break;
int l1=i-h2+1;
int l2=len-1-l1;
if(l2==0) can=false;
rt->l= mktree(h1+1,h2,l1);
rt->r=mktree(h1+1+l1,i+1,l2);
return rt;
}
void inorder(node *rt){
if(rt){
inorder(rt->l);
v.push_back(rt->val);
inorder(rt->r);
}
}
int main(){
cin>>n;
for(int i=1;i<=n;i++) cin>>pre[i];
for(int i=1;i<=n;i++) cin>>pos[i];
node *rt= mktree(1,1,n);
if(can) cout<<"Yes"<<endl;
else cout<<"No"<<endl;
inorder(rt);
for(int i=0;i<v.size();i++){
if(i) cout<<' ';
cout<<v[i];
}
cout<<endl;
return 0;
}
堆
二叉堆是完全二叉树。(可以不是满二叉树)
只分为大顶堆,小顶堆
数组原地建堆:(建堆,代表结构为堆,但是依次输出的不是有序的)
方法一:Heapify
时间复杂度:O(n)
操作:
从每一个父结点开始,向下找数,和父结点交换。
第一个非叶子结点:
a.length/2-1;
int arr[]= {3,2,4,5,3,6};
//数组建堆
for(int i=arr.length/2-1;i>=0;i--)//arr.length/2-1为第一个非叶结点
{
adjustHeap(arr, i, arr.length);//根据升序降序选择大顶堆小顶堆
}
public static void adjustHeap(int arr[],int i,int length)//调整堆
{
int temp=arr[i];//i后面一直变化
for(int k=i*2+1;k<length;k=k*2+1)
{
if(k+1<length&&arr[k]<arr[k+1])//右子节点大于左子节点
{
k++;
}
if(arr[k]>temp)//和原来的作比较
{
arr[i]=arr[k];i=k;
}
else {
break;//两边节点都没有更大的
}
}
arr[i]=temp;//赋值
}
方法2:HeapInsert
时间复制度:O(nlogn)
操作:
数先放入底部
向上找父节点,进行交换。
int n=8;
int a[100]={46,23,26,24,10,34,22,55};
void buildheap1(int x,int index)//这个比较好理解
{
//数先放入底部
// 10 23 22 24 46 34 26 55
int t=index;
a[index]=x;
while(t>0&&(a[(t-1)/2]>a[t]))
{
a[t]=a[(t-1)/2];
a[(t-1)/2]=x;
t=(t-1)/2;
}
a[t]=x;
}
int main()
{
for(int i=0;i<n;i++)
{
buildheap1(a[i],i);
}
for(int i=0;i<8;i++)
cout<<a[i]<<" ";
return 0;
}
//这个简化的代码量
//原理不变
//先把数据存到最底部
//往上找数,进行交换
int n=8;
int a[100]={46,23,26,24,10,34,22,55};
void swap(int x,int y)
{
int t=a[x];
a[x]=a[y];
a[y]=t;
}
void buildheap2(int x,int index)
{
while(index>0&&(a[(index-1)/2]>a[index]))
{
swap(index,(index-1)/2);
index=(index-1)/2;
}
}
int main()
{
for(int i=0;i<n;i++)
{
buildheap2(a[i],i);
}
for(int i=0;i<8;i++)
cout<<a[i]<<" ";
return 0;
}
堆排序
步骤:
1,数组原地建堆
package 堆排序;
//2021年3月30日下午2:28:55
//writer:apple
public class 堆排序2 {
public static void main(String[] args) {
// TODO Auto-generated method stub
int arr[]= {3,2,4,5,3,6};
Heapsort(arr);
for(int i:arr)
System.out.print(i+" ");
}
public static void adjustheap(int arr[],int i,int size)
{
int temp=arr[i];
for(int k=i*2+1;k<size;k=k*2+1)
{
//大根堆,为升序
// if((k+1)<size&&arr[k+1]>arr[k])
// {
// k++;
// }
// if(arr[k]>temp)
// {
// arr[i]=arr[k];
// i=k;
// }
// else break;
//小根堆,为降序。
if((k+1)<size&&arr[k+1]<arr[k])
{
k++;
}
if(arr[k]<temp)
{
arr[i]=arr[k];
i=k;
}
else break;
}
arr[i]=temp;
}
/*public static void buildheap(int arr[])
{
for(int i=arr.length/2-1;i>=0;i--)
{
adjustheap(arr, i, arr.length);
}
}*/
public static void Heapsort(int arr[])
{
//buildheap过程
for(int i=arr.length/2-1;i>=0;i--)
{
adjustheap(arr, i, arr.length);
}
//排序
for(int i=arr.length-1;i>0;i--)
{
int temp=arr[0];
arr[0]=arr[i];
arr[i]=temp;
adjustheap(arr, 0, i);
}
}
}
c++版本:
#include<bits/stdc++.h>
using namespace std;
void heapadjust(int a[],int idx,int size){//向下调整,找大的上来
int child=idx*2+1;
while(child<size){
if(child+1<size&&a[child+1]>a[child]) child++;
if(a[child]>a[idx]){
swap(a[child],a[idx]);
idx=child;
child=child*2+1;
}else break;
}
}
void heapsort(int a[],int size){
for(int i=size/2-1;i>=0;i--){//从最后一个非叶子开始调整堆,是一种优化
heapadjust(a,i,size);
}
for(int i=size-1;i>0;i--){//缩小size大小,进行排序。大的会被置后,所以是升序
swap(a[i],a[0]);
heapadjust(a,0,i);
}
}
int main()
{
int a[5]={34,12,453,53,3};//从0 开始,孩子为(2*n+1,2*n+2)
heapsort(a,5);
for(int i=0;i<5;i++) cout<<a[i]<<" ";
return 0;
}
判断大小堆:
bool ismax(){
for(int i=1;i<=n;i++){
if(i*2<=n){
if(a[i*2]>=a[i]) return false;
}else break;
if(i*2+1<=n){
if(a[i*2+1]>=a[i]) return false;
}
}
return true;
}
bool ismin(){
for(int i=1;i<=n;i++){
if(i*2<=n){
if(a[i*2]<=a[i]) return false;
}else break;
if(i*2+1<=n){
if(a[i*2+1]<=a[i]) return false;
}
}
return true;
}