DataStructure_堆&树&BST

1.堆
堆其实就是一棵树,不过可用范围主要集中在堆顶
由此 我们拥有了大根堆&小根堆 然而我不会
一道手写堆 体验一下是极好的,尤其是堆的siftdown
洛谷P1878 舞蹈课
附上大佬的ac码(菜如我只能借鉴了qwq)

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
struct node{
 int val,l,r;
 //重载运算符 靠左优先 
 //结构体重载运算符要加friend (要用两个变量的话)
 friend bool operator>(node n1,node n2){
  return n1.val>n2.val || (n1.val==n2.val && n1.l>n2.l);
 }
 friend bool operator <(node n1,node n2){
  return n1.val<n2.val ||(n1.val==n2.val && n1.l< n2.l);
 }
 //或者像这样
 /*
  bool operator>(const node& n2) const {
  return val>n2.val || (val==n2.val && l>n2.l);
 }
 bool operator<(const node& n2)const {
  return val<n2.val ||(val==n2.val && l< n2.l);
 }
 */
} a[2000006];

int n,v[200006],cnt,ansl[200005],ansr[200005],HeapSize;
bool vis[200005],f[200005];
node heap[200005];
string s;
//这里重点就是这个手写堆辣
void insert(int val,int l,int r){
 int now=++HeapSize;
 int nxt;
 //先把他放到最底下 再往上调整
 heap[HeapSize].val=val;
 heap[HeapSize].l=l;
 heap[HeapSize].r=r;
 while(now>1){
 //右移操作
  nxt=now>>1;
  //如果碰到的地方已经比他小了 那么它到了自己的位置了
  if(heap[now]>heap[nxt]) return ;
  //如果没有,那就要往上调整
  else swap(heap[now],heap[nxt]);
  now=nxt;
 }
 return ;
 
//出堆 这是小根堆 堆顶最小 
void Get(){
 int now=1;
 int nxt;
 //把堆底的一个元素 覆盖掉顶
 //这样堆的起始序号还是从1开始,节约空间 
 heap[1].val=heap[HeapSize].val;
 heap[1].l=heap[HeapSize].l;
 heap[1].r=heap[HeapSize].r;
 HeapSize--; 
 //然后把它往下面推 同理
 while(now<< 1 <= HeapSize){
  nxt=now<<1;
  //这个二分的操作真的好神奇呀
  //保持左右子树的稳定性 换到右子树上
  if(nxt< HeapSize && heap[nxt]>heap[nxt+1]) nxt++; 
  if(heap[nxt]>heap[now]) return ;
  else swap(heap[now],heap[nxt]);
  now=nxt; 
 } 
 return;
}
void print(){
 cout << cnt <<endl;
 for(int i=1;i<=cnt;i++){
  cout << ansl[i]<<" "<<ansr[i]<<endl;
 }
 return ;
}
int main(){
 cin >>n;
 cin >> s;
 for(int i=1;i<=n;i++)
  cin>>v[i];
 for(int i=1;i<=n;i++)
  f[i]=(s[i-1]=='B')? 1: 0;
 for(int i=1;i<=n;i++){
  int nxt=i+1;
  if(nxt<=n && f[i]!=f[nxt]){
   insert(abs(v[i]-v[nxt]),i,nxt);
  }
 } 
 while(HeapSize){
  int l=heap[1].l;
  int r=heap[1].r;
  int curl,curr;
  vis[l]=1;vis[r]=1;
  ansl[++cnt]=l;
  ansr[cnt]=r;
  do{
   Get();
   if(!HeapSize) break;
   //当前的值 
   curl=heap[1].l;
   curr=heap[1].r;
  }
  while(vis[curl] || vis[curr]);
  while(l && vis[l]) l--;
  while(r<=n && vis[r]) r++;
  if(l && r <=n && f[l]!=f[r])insert(abs(v[l]-v[r]),l,r); 
 }
 print();
 return 0;
} 

2.树
(1)一般都是二叉树

  • 满二叉树与完全二叉树的辨别:
    嘤 满二叉树一定和完全二叉树没有必然联系8,
    (Full binary tree) 满二叉树要求每个非叶子结点都要有左右儿子。
    (Complete binary tree) 完全二叉树要求排布顺序,要求严格按照左根右的顺序出现节点。
    这种 看图就好了(xx

(2)基本操作 声明,建树,遍历,查询和插入(都是基础的维护操作)

  • 插播一个树的遍历 分为前序中序后序,意思就是在访问节点时根节点的访问次序: 前序:根左右 中序:左根右 后序:左右根 挺好记住的,以及遍历的时候递归地按照这个规则就好辣
  • 知识点:霍夫曼编码树(很有意思 值得一学) 可以优化取字母的效率
    *两个板子(链表版+数组版)

以及放个题 巨佬们的树写的很漂亮呜呜呜
果然还是不喜欢链表版的树
线段树—查找最后一个大于指定元素的位置

#include<iostream>
#include<string>
#include<algorithm>
using namespace std;
//en,题意相当清晰
//求ai右边最后一个至少比ai大m的数与它的距离
//线段树 
const int maxn=500005;
int n,m;
int x[maxn],ans[maxn],w[maxn],Tree[maxn<<2]; 
void pushup(int rt){
 Tree[rt]=max(Tree[rt<<1|1],Tree[rt<<1]);
}
void update(int pos,int val,int l,int r,int rt){
 if(l==r){
  Tree[rt]=val;
  return ;
 }
 int mid=(l+r)>>1;
 if(pos<=mid) update(pos,val,l,mid,rt<<1);
 else update(pos,val,mid+1,r,rt<<1|1);
 pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
 if(L<=l&&R>=r){
  return Tree[rt];
 }
 int ans=0;
 int mid=(l+r)>>1;
 if(mid>=L) ans=max(ans,query(L,R,l,mid,rt<<1));
 if(mid<=R) ans=max(ans,query(L,R,mid+1,r,rt<<1|1));
 return ans; 
}
int main(){
 cin >> n >>m;
 for(int i=1;i<=n;i++){
  cin>>w[i];
  x[i]=w[i];
 }
 sort(x+1,x+1+n);
 //去重要记得多减去一个1 qwq 
 int len=unique(x+1,x+1+n)-x-1;
 for(int i=1;i<=n;i++){
  int pos=lower_bound(x+1,x+1+len,w[i])-x;
  update(pos,i,1,len,1); 
 } 
 for(int i=1;i<=n;i++){
  int pos=lower_bound(x+1,x+1+len,w[i]+m)-x;
  //According to the question,dis=r-l-1. 
  ans[i]=query(pos,len,1,len,1)-i-1;
  if(ans[i]<0) ans[i]=-1; 
 }
 for(int i=1;i<n;i++)cout << ans[i]<<" ";
 cout << ans[n]<<endl;
 return 0;
}

板子 勉强能看懂了 什么时候能自己写个啊qwq
找后l个元素中最大的那个-线段树可写

#include<iostream>
#include<cmath>
#include<string.h>
#include<stdio.h>
#include<iomanip>
#include<algorithm>
#include<queue>
#include<vector>
using namespace std;
const int inf = 0x3f3f3f;
int n,q[12345678],t=0,root=1,m=1,inputi;
long long d=0;
char inputc;
void build(int l,int r,int rt){
 q[rt]=-inf;
 if(l==r) return;
 int m=(l+r)>>1;
 build(l,m,rt<<1);
 build(m+1,r,rt<<1|1); 
}
void plusa(int l,int r,int rt,int p,int v){
 if(l==r) {
  q[rt]=v;
  return ;
 }
 int m=(l+r)>>1;
 if(p<=m) plusa(l,m,rt<<1,p,v);
 else plusa(m+1,r,rt<<1|1,p,v);
 q[rt]=max(q[rt<<1],q[rt<<1|1]);
}
int sth;
int ask(int l,int r,int rt,int nl,int nr){
 if(nl<=l&&nr>=r) return q[rt];
 int m=(l+r)>>1;
 int minn=-inf;
 if(nl<=m) minn=ask(l,m,rt<<1,nl,nr);
 if(nr>m) minn=max(minn,ask(m+1,r,rt<<1|1,nl,nr));
 return minn; 
}
int main(){
 cin >> m>>d;
 build(1,m,1);
 for(int i=1;i<=m;i++){
  cin>>inputc>>inputi;
  if(inputc=='A'){
   plusa(1,m,1,++sth,(inputi+t)%d);
  }
  else{
   t=ask(1,m,1,sth-inputi+1,sth);
   cout<<t<<endl;
  }
 }
 return 0;
}

给个链表版的BST&一个霍夫曼树qwq
真实写了好久(显然是借鉴大佬们的
数组的设置非常弱智 有空再改啊,其实是多余的
(可以实现从txt中读取一串不区分大小写的字母,进行霍夫曼编码并输出)
*BST

#include<iostream>
using namespace std;
/*建立一个含有n个结点的二叉检索树,使用指针实现,并在此基础上分别设计一个主程序完成如下功能:
- 通过键盘输入两个结点序列分别构建两个二叉检索树,要求结点值在0~100之间,结点数量不少于8个;
- 输出该二叉检索树的顺序表示(见教材6.5节,"/"代表空指针NULL);
- 输出对该树的前序遍历、中序遍历、后续遍历的结果;观察各遍历输出结果,哪一种遍历将结点按照从小到大进行了排列; 
- 输出该树的叶子结点的数量及叶子结点的值;
*/
int a[400],b[400];
//int a[40]={0 15 54 676 3 777 6 7 8 34 2 5};
//int b[40]={0 18 9 10 4 2 3 68 30 23 66};
int cnt=0;
int leaf[40];
struct node{
 int data;
 node* lc;
 node* rc;
};
node * rt1=NULL;
node * rt2=NULL;
node * newNode(int v){
 node * Node = new node;
 Node->data=v;
 Node->lc = Node->rc = NULL;
 return Node;
}
void insert(node* &now,int x){
 if(now==NULL){
  now=newNode(x);
  return;
 }
 if(now->data == x){
  return;
 }
 else if(x< now->data){
  insert(now->lc,x);
 }
 else insert(now->rc,x);
}
node* Build(int data[],int n,node* &rt){
 for(int i=1;i<=n;i++){
  insert(rt,data[i]);
 } 
 return rt;
}
void preorder(node *now){
 if(now==NULL) return;
 cout<<now->data<<" ";
 preorder(now->lc);
 preorder(now->rc);
 return;
}
void inorder(node *now){
 if(now==NULL) return ;
 inorder(now->lc);
 cout<<now->data<<" ";
 inorder(now->rc);
 return ;
} 
void postorder(node *now){
 if(now==NULL) return ;
 postorder(now->lc);
 postorder(now->rc);
 cout<<now->data<<" ";
 return;
}
void Print(node *now){
 if(now==NULL) {
  cout<<"/ ";
  return;
 }
 cout<<now->data<<" ";
 Print(now->lc);
 Print(now->rc);
 return ;
}
void CountLeaf(node *now){
 if(now==NULL) return ;
 if(!now->lc && !now->rc){
  leaf[++cnt]=now->data;
 }
 CountLeaf(now->lc);
 CountLeaf(now->rc);
 return ;
}
void test(node * &rt,int aa[],int l){
 Build(aa,l,rt);
 cout<<endl<<"【前序遍历】:Preorder trasveral: ";
 preorder(rt);
 cout<<endl<<"【中序遍历】:Inorder trasversal: ";
 inorder(rt);
 cout<<endl<<"【后序遍历】:Postorder traversal: ";
 postorder(rt);
 cout<<endl;
 CountLeaf(rt);
 cout<<endl<<"【输出叶子节点】"<<endl<<"This BST has "<<cnt<<" LeafNodes, there are: ";
 for(int i=1;i<=cnt;i++){
  cout << leaf[i]<<" ";
 }
 cout<<endl;
 //for(int i=1;i<=cnt;i++)cout<<"(";
 cout<<endl<<"【顺序表示法】: "; 
 Print(rt);
 cout<<endl; 
}
void ini(){
 for(int i=1;i<=cnt;i++)leaf[i]=0;
 cnt=0;
}
int main(){
 int t=2;
 while(t--){
  int x;
  cout<<"Print the number"<<endl;
  cin>>x;
  for(int i=1;i<=x;i++){
   cin>>a[i];
  }
  node *newrt = new node;
  newrt=NULL;
  cout<<"The first BST:"<<endl;
  test(newrt,a,x);
  ini();
  for(int i=1;i<=100;i++)cout<<'-';
  cout<<endl;
 }
 return 0;
}

*霍夫曼

#include<iostream>
#include<fstream>
#include<string.h>
using namespace std;
//input from a txt
fstream fin;
/*
int f[50]={0,7,9,2,6,32,3};
char a[50]={'A','B','C','D','E','F','G'};
*/
int count=0;
int cnt[50],t[50];
char word[50];
int tmp[1000];
struct HNode{
 int w;
 char c;
 HNode *lc,*rc;
 //if it is in the queue
 //if used, will not use it again
 bool flag;
 HNode(){
  flag=1;
  w=0;
  c='0';
  lc=rc=NULL;
 }
 //initiate
 HNode(int ww,char cc,HNode* l,HNode *r):w(ww),c(cc),lc(l),rc(r),flag(1){
 };
};
class Huffman{
 public:
 HNode *rt;
 HNode* forest[5000];
  int cnt;
  void Build(int f[],char a[],int size){
   int k=0;
   for(int i=1;i<=size;i++){
    HNode *newnode = new HNode(f[i],a[i],NULL,NULL);
    forest[i]=newnode;
   }
   for(int i=1;i<size;i++){
    //cout<<forest[i]->w<<endl;
    //sort the tree leaves in order
    newsort(size+k);
    for(int j=1;;j++){
     if(forest[j]->flag==1&&forest[j+1]->flag==1){
      HNode *newnode = new HNode(forest[j]->w+forest[j+1]->w,'0',forest[j],forest[j+1]);
      k++;
      forest[size+k]=newnode;
      //cout<<forest[j]->c<<" and "<<forest[j+1]->c<<endl;
      //cout<<"new node w: "<<newnode->w<<endl; 
      forest[j]->flag=0;
      forest[j+1]->flag=0;
      break;
     }
     else continue;
    }
   }
   rt=forest[size+k];
  }
  //if we find the character we need, output the answer(code of it)
  void PrintAns(char c,int x){
   cout<<" "; 
   for(int i=1;i<x;i++)
   cout<<tmp[i];
   return;
  }
  void printCode(HNode *now,char t,int x){
   if(now==NULL) return;
   if(now->c == t){
    PrintAns(t,x); 
   }
   //book the answer
   tmp[x]=0;
   printCode(now->lc,t,x+1);
   tmp[x]=1;
   printCode(now->rc,t,x+1);
   return;
  }
  void inorder(HNode* now){
   if(now!=NULL){
    inorder(now->lc);
    cout<<now->w<<" ";
    //if(now->c>='A'&&now->c <='Z')
    //cout<<now->c<<" ";
    //cout<<now->w<<" ";
    inorder(now->rc); 
   } 
  }
  void newsort(int size){
   //Bubble5sort
   for(int i=1;i<size;i++)
   {
    for(int j=i+1;j<=size;j++){
     if(forest[j]->w < forest[i]->w){
      swap(forest[i],forest[j]);
     }
    }
   }
  }
 private:
 protected:
};
//process the input
void process(string x){
 int l=x.length();
 for(int i=0;i<l;i++)
  if(x[i]>='a'&&x[i]<='z')
   x[i]=char(x[i]+'A'-'a');
 for(int i=0;i<l;i++)
  t[x[i]-'A'+1]++;
}
int main(){
 cout<<"Input a text as follows:"<<endl<<endl;
 fin.open("data.txt");
 while(fin){
  string x;
  fin>>x;
  cout<<x<<endl; 
  process(x);
 }
 cout<<"Frequency:"<<endl<<endl;
 for(int i=1;i<=26;i++){
  if(t[i]){
   word[++count]=char(i+'A'-1);
   cnt[count]=t[i];
   cout<<" "<<word[count]<<" :"<<cnt[count]<<endl;
  }
 }
 cout<<endl;
 Huffman Tree;
 for(int i=1;i<=10;i++)cout<<'-';
 cout<<endl<<"Codes:"<<endl; 
 Tree.Build(cnt,word,count);
 //for every char appears in the tree, output the codes.
 for(int i=1;i<=count;i++){
  cout<<"  ("<<i<<")"<<word[i]<<":";
  Tree.printCode(Tree.rt,word[i],1);
  cout<<endl;
 }
 return 0;
}
发布了24 篇原创文章 · 获赞 2 · 访问量 959

猜你喜欢

转载自blog.csdn.net/weixin_43521836/article/details/101108009
BST