数据结构复习笔记【上】【更新中】

线性表

顺序表

在这里插入图片描述
在这里插入图片描述

#include <iostream>
using namespace std;
class List{
    int *list;
    int maxsize;
    int size;
public:
    List(){
        maxsize=1000;
        size=0;
        list=new int[maxsize];
        int len;
        cin>>len;
        for(int i=1;i<=len;i++){
            cin>>list[i];
            size++;
        }
    }
    void insert(int pos,int key){
        if(pos>size+1||pos<1){
            cout<<"error"<<endl;
            return;
        }
        for(int i=size;i>=pos;i--){
            list[i+1]=list[i];
        }
        list[pos]=key;
        size++;
        display();
        return;
    }
    void deleteKey(int pos){
        if(pos>size||pos<1){
            cout<<"error"<<endl;
            return;
        }
        for(int i=pos;i<=size;i++){
            list[i]=list[i+1];
        }
        size--;
        display();
        return ;
    }
    void searchKey(int pos){
        if(pos>size||pos<1){
            cout<<"error"<<endl;
            return;
        }
        cout<<list[pos]<<endl;
    }
    void display(){
        cout<<size<<" ";
        for(int i=1;i<=size;i++){
            cout<<list[i]<<" ";
        }
        cout<<endl;
    }
 
    void operation(){
        display();
        int pos,key;
        cin>>pos>>key;
        insert(pos,key);
        cin>>pos>>key;
        insert(pos,key);
        cin>>pos;
        deleteKey(pos);
        cin>>pos;
        deleteKey(pos);
        cin>>pos;
        searchKey(pos);
        cin>>pos;
        searchKey(pos);
    }
};
int main()
{
    List list;
    list.operation();
    return 0;
}

需要注意的地方:

  1. 下标从1开始(因此遍历是for(int i=1;i<=n;i++))
  2. 每插入或删除一个元素,size要改变
  3. 删除和查找的位置的异常位置是小于1或者大于size,但是插入的位置可以是size+1,(比如6个元素,可以在第7个位置插入)
  4. 由于判断是否出错,出错的话如果在函数内部输出,那么此时如果正确的话,链表信息展示也应该在函数内部输出

部分习题选取:
在这里插入图片描述
思路,先创建一个顺序表,用第一行的输入创建,然后第二行读取每个字符的时候,就插到对应位置上。
用a>list[i]&&a<list[i+1]来找到位置,如果到最后一个位置了就直接插入
找到对应的位置后调用之前写好的insert函数进行插入。

链表

在这里插入图片描述
在这里插入图片描述

#include <iostream>
 
using namespace std;
class Node{
public:
    int data;
    Node *next;
    Node(){next=NULL;}
};
class List{
    Node *head;
    int len;
public:
    List(){
        head=new Node;
        cin>>len;
        for(int i=0;i<len;i++){
            int data;
            cin>>data;
            Node *p=new Node;
            p->data=data;
            Node *q=head;
            while(q->next)q=q->next;
            q->next=p;
        }
    }
    void Operation(){
        int pos,data;
        cin>>pos>>data;
        insertNode(pos,data);
        cin>>pos>>data;
        insertNode(pos,data);
        cin>>pos;
        deleteNode(pos);
        cin>>pos;
        deleteNode(pos);
        cin>>data;
        searchNode(data);
        cin>>data;
        searchNode(data);
    }
    void insertNode(int pos,int data){
        len++;
        Node *p=head;
        if(pos>len+1||pos<1){
            cout<<"error"<<endl;
            return;
        }
        for(int i=0;i<pos-1;i++)p=p->next;
        Node *q=new Node;
        q->data=data;
        q->next=p->next;
        p->next=q;
        display();
    }
    void deleteNode(int pos){
        len--;
        if(pos<1||pos>len){
            cout<<"error"<<endl;
            return ;
        }
        Node *p=head;
        for(int i=0;i<pos-1;i++)p=p->next;
        Node *q=p->next;
        p->next=p->next->next;
        delete q;
        display();
    }
    void searchNode(int pos){
        if(pos<1||pos>len){
            cout<<"error"<<endl;
            return ;
        }
        Node *p=head;
        for(int i=0;i<pos;i++)p=p->next;
        cout<<p->data<<endl;
    }
    void display(){
        Node *p=head->next;
        while(p){
            cout<<p->data<<" ";
            p=p->next;
        }
        cout<<endl;
    }
};
int main()
{
    List list1;
    list1.display();
    list1.Operation();
    return 0;
}

需要注意的地方:

  1. 初始化时不要忘记结点需要这一条构造函数: Node(){next=NULL;}
  2. 创建链表时不要忘记初始化头结点head=new Node;
  3. 在display函数中,不能输出头结点的值,因为头结点不存储值:因此一开始初始化就应该Node *p=head->next;
  4. 对于插入来说,比如我要在第五个位置插入结点,那应该将结点移动到第四个结点,然后再新生成一个结点,让第四个结点指向它
  5. 对于删除来说,比如要删除第五个位置的结点,则需要移动到第四个结点,并且还额外需要一个结点来指向第五个结点,后面delete掉它
    for(int i=0;i<pos-1;i++)p=p->next;
    Node *q=p->next;
    p->next=p->next->next;
  6. 遍历链表的时候不要忘记p=p->next
  7. 插入和删除结点的时候不要忘记改变长度
  8. 插入或删除失败时会在函数内部输出error,因此成功时也应该在函数内部输出,或者要么统一在外面输出

习题:
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
思路:对于所有元素,我们都这样遍历链表,用q->next来遍历,如果q->next的后一个元素与该次遍历的元素相同,则删除q->next的元素,如果不相同则往后移

void L_del(){
        ListNode *p,*q,*s;

        p=head->next;
        while(p){
            q=p;
            while(q->next){
                if(q->next->data==p->data){ //当删除了一个结点后,q不往后移,下次重新判定
                    s=q->next;
                    q->next=q->next->next;
                    delete s;
                    len--;
                }
                else
                  q=q->next;
            }
            p=p->next;
        }
    }

堆栈

stack类使用的参考代码

  1. 包含头文件 : #include
  2. 创建一个堆栈对象s(注意stack是模板类):stack s; //堆栈的数据类型是字符型
  3. 把一个字符ct压入堆栈: s.push(ct);
  4. 把栈顶元素弹出:s.pop();
  5. 获取栈顶元素,放入变量c2: c2 = s.top();
  6. 判断堆栈是否空: s.empty(),如果为空则函数返回true,如果不空则返回false

习题:
在这里插入图片描述在这里插入图片描述
算法流程

  1. 初始化,i=0,建立堆栈,栈为空

  2. 输入表达式,建立指针指向表达式的头部

  3. 读入表达式的第i个字符

  4. 如果第i个字符是左括号,入栈

  5. 如果第i个字符是右括号,检查栈顶元素是否匹配

    A.如果匹配,弹出栈顶元素

    B.如果不匹配,报错退出

  6. i++,指向下一个字符,是否已经表达式末尾

    A. 未到末尾,重复步骤3

    B. 已到达末尾

    a. 堆栈为空,输出ok
    
    b. 堆栈不为空,输出error
    

代码:

#include <iostream>
#include<stack>
using namespace std;
 
int main()
{
    int t;
    cin>>t;
    while(t--){
        int flag=1;
        string a;
        cin>>a;
        stack<char> b;
        for(int i=0;i<a.length();i++){
            if(a[i]=='('||a[i]=='['||a[i]=='{'){
               b.push(a[i]);
            }
            if(a[i]==')'||a[i]==']'||a[i]=='}'){
                if(a[i]==')'){
                    if(b.top()=='(')b.pop();
                    else{
                        flag=0;
                        break;
                    }
                }
                else if(a[i]==']'){
                    if(b.top()=='[')b.pop();
                    else{
                        flag=0;
                        break;
                    }
                }
                else if(a[i]=='}'){
                    if(b.top()=='{')b.pop();
                    else{
                        flag=0;
                        break;
                    }
                }
            }
        }
        while(!b.empty()){
            if(b.top()=='('||b.top()=='['||b.top()=='{'){
                flag=0;
                break;
               }
            b.pop();
        }
 
        if(flag==1)cout<<"ok"<<endl;
        else cout<<"error"<<endl;
    }
    return 0;
}

在这里插入图片描述

在这里插入图片描述
思路,需要有两个栈,一个栈存放访问过的网站,一个栈存放因为BACK,然后需要将这些网站放到另一个栈中。
此时如果访问新的网站,则需要将第二个栈的内容全部清空。

#include <iostream>
#include<stack>>
using namespace std;
 
int main()
{
    stack<string> a;
    stack<string> c;
    a.push("http://www.acm.org/");
    while(1){
        string b;
        cin>>b;
        if(b[0]=='V'){
            string web;
            cin>>web;
            a.push(web);
            cout<<a.top()<<endl;
            while(!c.empty())c.pop();
        }
        else if(b[0]=='B'){
            if(a.empty())cout<<"Ignored"<<endl;
            else {
                string now=a.top();
                a.pop();
                if(a.empty()){
                   cout<<"Ignored"<<endl;
                   a.push(now);
                   continue;
                }
                c.push(now);
                cout<<a.top()<<endl;
            }
        }
        else if(b[0]=='F'){
            if(c.empty()){
                cout<<"Ignored"<<endl;
                continue;
            }
            else{
                cout<<c.top()<<endl;
                a.push(c.top());
                c.pop();
            }
        }
        else if(b[0]=='Q'){
            break;
        }
    }
 
}

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
说实话这题有点难,不知道会不会考这种类型的,先暂时不复习了

#include<bits/stdc++.h>
using namespace std;
#define OK 0
#define ERROR -1
#define OVERFLOw -1
#define OPSETSIZE 7 //运算符号集合长度,目前只有7个符号
 
typedef int status;
 
char OPSET[7]={'+','-','*','/','(',')','#'};//运算符集合
bool In(char Test,char* TestOp){//判断字符Test是否是运算符
    for(int i=0;i<7;i++)
        if(Test==TestOp[i])
           return true;
    return false;
    }
 
 
char Prior[7][7]={{'>','>','<','<','<','>','>'},{'>','>','<','<','<','>','>'},
{'>','>','>','>','<','>','>'},{'>','>','>','>','<','>','>'},{'<','<','<','<','<','=',' '},
{'>','>','>','>',' ','>','>'},{'<','<','<','<','<',' ','='}
                   };
 
char precede(char Aop,char Bop){
    int x,y;
    for(int i=0;i<7;i++){
        if(Aop==OPSET[i])x=i;
    }
    for(int i=0;i<7;i++){
        if(Bop==OPSET[i])y=i;
    }
    return Prior[x][y];
}
 
float Operate(float a,unsigned char theta,float b){
    float result;
    if(theta=='+')result=a+b;
    if(theta=='-')result=a-b;
    if(theta=='*')result=a*b;
    if(theta=='/')result=a/b;
    return result;
}
float EvaluateExpression(string MyExp){
//算术表达式求值的算符优先算法。
//设OPTR和OPHD芬别为运算符转和运算数栈,_oP为运算符集合。
    stack<char> OPTR;//运算符栈,字符元素_
    stack <double> OPND;//运算数栈,实数光素
    char TempData[20];
    double Data,a,b,r;
    char theta,Dr[2];
    char c;
    int i=0;//用于控制字符串的位置移动
    //InitStack (OPTR); InitStack(OPND);两行代码无用去掉
    //Push(OPTR,'#');C =MuExpression;原有两行代码改造为下面两句
    OPTR.push('#');
    c=MyExp[0];
    strcpy(TempData,"\0");
    while(c!='#'||OPTR.top()!='#'){
        if(!In(c,OPSET)){
            Dr[0]=c;
            Dr[1]='\0';
            strcat(TempData,Dr);
            c=MyExp[++i];//读下——个字符
            if(In(c,OPSET)) {
            Data=(float)atof(TempData);
            OPND.push(Data);
            //l---------致造上—句代码为—句c++代码
            strcpy(TempData,"\0");
            }//c是运算符,表明前面读入了一个完整操作数
        } //读入的字符不是运算符,是1个数字
 
 
 
        else {//是运算符,开始进行计算
            switch (precede(OPTR.top(),c)){
                case '<'://栈顶元素优先校低
                OPTR.push(c);
                //i ---------攻造上—包伐码为一句c++代码
                i++;
                c=MyExp[i];
                //il..-------读下一个字符
                break;
                case '='://脱括号并接收下一字符
                OPTR.pop();
                // ---------改造上一包伐码为1-2句C++代码
                i++;
                c=MyExp[i];
                //, ---------读下—个字符
                break;
                case '>'://退栈并将运算结果入栈
                theta=OPTR.top();
                OPTR.pop();//Pop(OPTR,theta);
                b=OPND.top();
                OPND.pop();  //Pop(OPND,b);
                a=OPND.top();
                OPND.pop(); //Pop(OPND, a)
                //Push(OPND,Operate(a,theta,b)
                OPND.push(Operate(a,theta,b));
                // ---------把上面四句代码改造成7-8司c++代码
                break;
                }
            }
    }
 
    return OPND.top();
     //---------改造上—司代码为一句c++代码
    // end function
 
}
 
int main(){
    string Exp;
    int t;
    double result;
    cin>>t;
    while (t--) {
    cin>>Exp;
    result = EvaluateExpression(Exp);
    cout<<fixed<<setprecision(4)<<result<<endl;
    }
    return 0;
}
 

在这里插入图片描述
在这里插入图片描述
样例输入
2
8
0 0 0 1 1 1 1 1
1 0 0 0 1 0 0 1
1 0 0 0 1 0 0 0
1 1 0 0 0 0 0 1
0 0 1 1 0 1 1 0
0 0 0 0 0 0 1 1
1 1 1 1 1 0 0 1
0 0 0 0 1 0 0 0
7
0 0 0 1 1 1 1
1 0 0 1 0 0 1
1 0 0 1 0 0 0
1 1 0 0 0 0 1
0 0 1 1 0 1 0
1 0 0 0 0 1 0
0 0 0 0 1 1 0
样例输出
[0,0]–[0,1]–[0,2]–[1,2]–
[1,3]–[2,3]–[3,3]–[3,4]–
[4,4]–[5,4]–[5,5]–[6,5]–
[6,6]–[7,6]–[7,7]–END
no path

队列

队列queue的用法如下:

  1. 包含头文件:#include
  2. 定义一个整数队列对象:queue myQe;
  3. 定义一个整数队列对象数组:queue myQe[10];
  4. 入队操作:myQe.push(itemp); //把整数itemp进入队列
  5. 出队操作:myQe.pop(); //把队头元素弹出队列,注意本操作不获取队头元素
  6. 获取队头元素: itemp = myQe.front(); // 把队头元素放入itemp中,注意本操作不弹出元素
  7. 判断队列是否为空:myQe.empty();//队列空则返回true,不空则返回false

在这里插入图片描述

#include <iostream>
#include<queue>
using namespace std;

int main()
{
    int num;
    cin>>num;
    queue<int> A;
    queue<int> B;
    for(int i=0;i<num;i++){
        int account;
        cin>>account;
        if(account%2==1){
            A.push(account);

        }
        if(account%2==0){
            B.push(account);
        }
    }
    while(!A.empty()&&!B.empty()){
        if(!A.empty()){
            cout<<A.front()<<" ";
            A.pop();
        }
        if(!A.empty()){
            cout<<A.front()<<" ";
            A.pop();
        }
        if(!B.empty()){
            cout<<B.front()<<" ";
            B.pop();
        }
    }
    while(!A.empty()){
        cout<<A.front()<<" ";
        A.pop();
    }
    while(!B.empty()){
        cout<<B.front()<<" ";
        B.pop();
    }

    return 0;
}

在这里插入图片描述
在这里插入图片描述
样例输入
2
19.125 2
15.125 16
样例输出
10011.001
F.200

#include <iostream>
#include<stack>
#include<queue>
using namespace std;
int main()
{
    int t;
    cin>>t;
    while(t--){
        stack<char> zs;
        queue<char> xs;
        double num;
        int k;
        cin>>num>>k;
        int zs1=num;
        double xs1=num-zs1;
//整数部分 zs:整数 xs:小数
        while(1){
            int ys=zs1%k;
            char ys1;
            if(ys>9){
                ys1=ys-10+'A';
            }
            else ys1=ys+'0';
            int s=zs1/k;
            zs1=s;
            zs.push(ys1);
            if(zs1==0)break;
        }
 
        while(!zs.empty()){
            cout<<zs.top();
            zs.pop();
        }
        cout<<".";
//小数部分
        int i=0;
        while(1){
            double j=xs1*k;//积
            int ys=(int)j;
            char ys1;//余数1
            if(ys>9){
                ys1=ys-10+'A';
            }
            else ys1=ys+'0';
 
            xs1=j-int(j);
            //cout<<j<<endl;
            xs.push(ys1);
            i++;
            if(xs1==0)break;
        }
        while(i<3){
            xs.push('0');
            i++;
        }
 
        while(!xs.empty()){
            cout<<xs.front();
            xs.pop();
        }
        cout<<endl;
 
 
 
    }
 
    return 0;
}

样例输入
9
0 20
1 15
1 61
2 10
10 5
10 3
30 18
31 25
31 2
3
样例输出
6.2 17 62

在这里插入图片描述

#include <iostream>
#include<queue>
#include<iomanip>
using namespace std;
 
int main()
{
    queue<int> a,b,c;
    int count;
    cin>>count;
    int num=0;
    int waittime[count];
    int ddtime[count],cltime[count];
    int nowtime=0;
 
    for(int i=0;i<count;i++){
        cin>>ddtime[i]>>cltime[i];
    }
    int k;
    cin>>k;
    while(1){
        /*if(a.empty()||b.empty()||c.empty()){
            cout<<"nowtime:"<<nowtime<<endl;
            count--;
            if(count==-1)break;
        }*/
        //cout<<nowtime<<" ";
        if(a.empty()&&nowtime>=ddtime[num]&&num<count){
            a.push(cltime[num]);
            waittime[num]=nowtime-ddtime[num];
            num++;
        }
        if(b.empty()&&nowtime>=ddtime[num]&&num<count){
            b.push(cltime[num]);
            waittime[num]=nowtime-ddtime[num];
            num++;
        }
        if(c.empty()&&nowtime>=ddtime[num]&&num<count){
            waittime[num]=nowtime-ddtime[num];
            c.push(cltime[num]);
            num++;
        }
        if(num==count&&(a.empty()&&b.empty()&&c.empty()))break;
        if(!a.empty()){
            int atime=a.front();
            //cout<<"A:"<<atime<<" ";
            a.pop();
            atime--;
            if(atime!=0)a.push(atime);
            else{
                if(a.empty()&&nowtime>=ddtime[num]&&num<count){
                a.push(cltime[num]);
                waittime[num]=nowtime-ddtime[num]+1;
                num++;
                }
            }
        }
        if(!b.empty()){
            int btime=b.front();
            //cout<<"B:"<<btime<<" ";
            b.pop();
            btime--;
            if(btime!=0)b.push(btime);
            else{
                if(b.empty()&&nowtime>=ddtime[num]&&num<count){
                b.push(cltime[num]);
                waittime[num]=nowtime-ddtime[num]+1;
                num++;
                }
            }
        }
        if(!c.empty()){
            int ctime=c.front();
            //cout<<"C:"<<ctime<<" ";
            c.pop();
            ctime--;
            if(ctime!=0)c.push(ctime);
            else{
                if(c.empty()&&nowtime>=ddtime[num]&&num<count){
                c.push(cltime[num]);
                waittime[num]=nowtime-ddtime[num]+1;
                num++;
                }
            }
        }
        //cout<<endl;
        nowtime++;
    }
 
    double waittimesum=0;
    int maxwaittime=0;
    for(int i=0;i<count;i++){
        //cout<<"wait"<<i+1<<":"<<waittime[i]<<endl;
        //waittime[i]+=1;
        if(waittime[i]>maxwaittime)maxwaittime=waittime[i];
        waittimesum+=waittime[i];
    }
    waittimesum/=count;
    cout<<fixed<<setprecision(1)<<waittimesum<<" ";
    cout<<maxwaittime<<" "<<nowtime;
    return 0;
}

在这里插入图片描述

在这里插入图片描述
样例输入
3
qwertyuiop
tyu
aabbccdd
ccc
aaaabababac
abac
样例输出
-1 0 0
5
-1 0 1
0
-1 0 0 1
8

#include<iostream>
#include<string>
using namespace std;
class myString {
    string mainstr;
public:
    void GetNext(string p, int next[]){
        int lenp=p.length();
        int k=-1;
        int j=0;
        next[0]=-1;
        while(j<lenp-1){
            if(k==-1||p[k]==p[j]){
                k++,j++;
                next[j]=k;
            }
            else k=next[k];
        }
    }
 
    void KMPFind(string p, int pos){
        int i=pos,j=0;
        int lenm=mainstr.length(),lenp=p.length();
        int *next=new int[lenp];
        GetNext(p,next);
        for(int k=0;k<lenp;k++){
            cout<<next[k]<<" ";
        }
        cout<<endl;
        int result;
        while(i<lenm&&j<lenp){
            if(j==-1||mainstr[i]==p[j]){
                i++,j++;
            }
            else j=next[j];
        }
        if(j>=lenp){
            result=i-lenp;
        }
        else result=-1;
        cout<<result+1<<endl;//result为0代表找不到的意思
    }
 
    myString(string a):mainstr(a){}
    ~myString(){
        mainstr = "";
    }
};
 
int main() {
    int t;
    cin >> t;//测试t次
    while (t--){
       string a,b;
       cin>>a>>b;
       myString c(a);
       c.KMPFind(b,0);
    }
    return 0;
}

代码的详细解析请看我的另一篇文章

KMP算法

习题:
在这里插入图片描述

一、利用kmp算法,取next数组中的最大值
#include <iostream>
#include <string>
using namespace std;

int GetMax(string s){
        int i, j,len=s.length();
        int *next=new int[len+1]; //注意:多求一次,即计算next[len],不然没法计算最后一个字符是重合的情况
        int max=-2;
        for(int k=0;k<len-1;k++){  //运行len-1次,每次从前面减少一个字符
           string p=s.substr(k);  //获取本次需计算next值的字符串,子串是从位置k开始到字符串尾
           next[0] = -1; j=0; i=-1;
           while (j < len ){
              if (i == -1 || p[j] == p[i]){
                 i++; j++; next[j] = i;
                 if(i>max)
                    max=i;
              }
              else
                 i = next[i];
           }

        }

        int result=max;
        if(max==len-1)//若整个字符串由单个字符组成
              result=len/2;
        else if(max>=len/2) //若有重叠部分
              result=len-max;
        else if(max==0)  //若没有重复子串
             result=-1;

        delete[] next;
        return result;
}

int main(){
  int t;
  string s;
  cin>>t;
  while(t--){
    cin>>s;
    cout<<GetMax(s)<<endl;
  }
  return 0;
}



因为如果长度大于一半,比如说总长度为8,kmp算出的最大next数组的值为5,那么中间肯定有重叠的部分
ABCABCAB

此时最大子串为总长度减去8-5=3

        else if(max>=len/2) //若有重叠部分
              result=len-max;

在这里插入图片描述
样例输入
3
aaa
abca
abcdefg
样例输出
0
2
7

需要注意一点,我们就是首先要找到最小循环节,然后把整个串补充成最小循环节的倍数。

还有就是一开始要给它加一个特别的字符,这样方便把最后一个字符也能算出它的next的值

#include<iostream>
#include<string>
using namespace std;
class myString {
    string mainstr;
public:
    void GetNext(string p, int next[]){
        int lenp=p.length();
        int k=-1;
        int j=0;
        next[0]=-1;
        while(j<lenp-1){
            if(k==-1||p[k]==p[j]){
                k++,j++;
                next[j]=k;
            }
            else k=next[k];
        }
    }

    void KMPFind(string p, int pos){
        int i=pos,j=0;
        int lenm=mainstr.length(),lenp=p.length();
        int *next=new int[lenp];
        GetNext(p,next);
        for(int k=0;k<lenp;k++){
            cout<<next[k]<<" ";
        }
        cout<<endl;
        int result;
        while(i<lenm&&j<lenp){
            if(j==-1||mainstr[i]==p[j]){
                i++,j++;
            }
            else j=next[j];
        }
        if(j>=lenp){
            result=i-lenp;
        }
        else result=-1;
        cout<<result+1<<endl;
    }

    myString(string a):mainstr(a){}
    ~myString(){
        mainstr = "";
    }
};

int main() {
    int t;
    cin >> t;
    while (t--){
        string a;
        cin>>a;
        a+='?';
        myString b(a);
        int *next=new int[a.length()];
        b.GetNext(a,next);
        if(next[a.length()-1]==0){
            cout<<a.length()-1<<endl;
            continue;
        }
        int circlelen=a.length()-1-next[a.length()-1];
        int uplen=circlelen-(a.length()-1)%circlelen;
        if((a.length()-1)%circlelen==0)
            uplen=0;
        cout<<uplen<<endl;


    }
    return 0;
}

而最小循环节就是用总长度减去next数组里的最后一个的值:

        int circlelen=a.length()-1-next[a.length()-1];

比如ABCA
循环节算出来是3
那么此时还需要补充多少呢
那得看最后一个循环节出现了几个
(a.length()-1)-circlelen也就是1 (A)
所以还需要补充BC形成ABC

但是如果是ABCABCA
这样的话,就不能简单的去减了
而是应该取余
应该用
(a.length()-1)%circlelen得到1
然后用3-1得到2

但是有一种特殊情况需要考虑,例如abcabcabc
此时循环节长度为3
(a.length()-1)%circlelen=0
uplen=circlelen-(a.length()-1)%circlelen=3
算出来uplen=3,这样就不对
所以对于这种情况需要特殊考虑:

        if((a.length()-1)%circlelen==0)
            uplen=0;

基本概念

在这里插入图片描述

在这里插入图片描述
二叉树性质:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

遍历二叉树

在这里插入图片描述

void PreOrderTraverse (BiNode*  T ) {
    if (T) {
        cout << T->data;
        PreOrderTraverse ( T->lChild );
        PreOrderTraverse ( T->rChild );
    }
}

在这里插入图片描述
中序遍历
在这里插入图片描述

void InOrderTraverse (BiNode*  T ) {
    if (T) {
	    InOrderTraverse ( T->lChild );
 	    cout << T->data;
        InOrderTraverse ( T->rChild );
    }
}

在这里插入图片描述

void PostOrderTraverse (BiNode*  T ) {
    if (T) {
	    PostOrderTraverse ( T->lChild );
	    PostOrderTraverse ( T->rChild );
	    cout << T->data;
     }
}

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
样例输入
2
AB#C##D##
AB##C##
样例输出
ABCD
BCAD
CBDA
ABC
BAC
BCA

#include <iostream>
 
using namespace std;
class treenode{
    public:
    char data;
    treenode *left,*right;
    treenode(){
        left=NULL,right=NULL;
    }
};
class tree{
    treenode *root;
public:
    tree(){
		root=cretabitree();
	}
    treenode* createbitree(){
        treenode *t;//一定要先创建一个结点,然后为其赋值
        char a;
        cin>>a;
        if(a!='#'){
            t=new treenode();
            t->data=a;
            t->left=createbitree();
            t->right=createbitree();
        }
        else t=NULL;
        return t;
    }
    void preorder1(treenode *t){
        if(t!=NULL){
            cout<<t->data;
            preorder1(t->left);
            preorder1(t->right);
        }
        else return;
    }
    void inorder1(treenode *t){
        if(t!=NULL){
            inorder1(t->left);
            cout<<t->data;
            inorder1(t->right);
        }
        else return;
    }
    void postorder1(treenode *t){
        if(t!=NULL){
            postorder1(t->left);
            postorder1(t->right);
            cout<<t->data;
        }
        else return;
    }
    void preorder(){
        preorder1(root);
    }
    void inorder(){
        inorder1(root);
    }
    void postorder(){
        postorder1(root);
    }
};
int main()
{
    int t;
    cin>>t;
    tree tree0;
    while(t--){
 
        tree0.createtree();
        tree0.preorder();
        cout<<endl;
 
        tree0.inorder();
        cout<<endl;
 
        tree0.postorder();
        cout<<endl;
    }
    return 0;
}

建树的错误写法:

    Tree(){
        root=new Node;
        createTree(root);
    }
    void createTree(Node *node){
        char data;
        cin>>data;
        if(data!='#'){
            node->data=data;
            createTree(node->left);
            createTree(node->right);
        }
        else node=null;
    }

不是把结点传进去,而是构造结点,然后将这个结点赋值给左右子树,因此建树的函数返回值应该是结点,不需要参数

正确写法:

 tree(){
		root=cretabitree();
	}
    treenode* createbitree(){
        treenode *t;//一定要先创建一个结点,然后为其赋值
        char a;
        cin>>a;
        if(a!='#'){
            t=new treenode();
            t->data=a;
            t->left=createbitree();
            t->right=createbitree();
        }
        else t=NULL;
        return t;
    }

在这里插入图片描述
原来的右边孩子消失,右边的兄弟(只包括亲兄弟不包括堂表弟)全部变成右孩子,左孩子不变
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

二叉树的顺序存储

在这里插入图片描述
在这里插入图片描述
样例输入
3
3 1 2 3
5 1 2 3 0 4
13 1 2 3 4 0 5 6 7 8 0 0 9 10
样例输出
1 2 3
1 2 4 3
1 2 4 7 8 3 5 9 10 6
提示
注意从数组位置和二叉树深度、结点位置进行关联,或者父子结点在数组中的位置存在某种管理,例如i, i+1, i/2, i+1/2…或者2i, 2i+1…仔细观察哦

#include <iostream>

using namespace std;
void preorder(int index,int tree[],int len){
    if(tree[index]!=0)cout<<tree[index]<<" ";
    if(index*2<=len)preorder(index*2,tree,len);
    if(index*2+1<=len)preorder(index*2+1,tree,len);
    return;
}
int main()
{
    int t;
    cin>>t;
    while(t--){
        int len;
        cin>>len;
        int *tree=new int[len+1];
        for(int i=1;i<=len;i++){
            cin>>tree[i];
        }
        preorder(1,tree,len);
        cout<<endl;
    }
    return 0;
}

二叉树的链式存储

在这里插入图片描述
样例输入
3
AB0C00D00
AB00C00
ABC00D00E00
样例输出
2
2
3

只需要在链式的遍历时:
在这里插入图片描述
加一条这样的语句

如果要判断其是不是左叶子结点
在这里插入图片描述

在这里插入图片描述
样例输入
3
AB0C00D00
AB00C00
ABCD0000EF000
样例输出
C D
B A
B C
A A
D F
C E

    void PreOrder(Node *node){
        if(node){
            //cout<<node->data;
            if(node->left==NULL&&node->right==NULL){
                cout<<node->data<<" ";
            }

            PreOrder(node->left);
            PreOrder(node->right);
        }
        else return;
    }

    void PreOrder2(Node *node){
        if(node){
            //cout<<node->data;
            if(node->left!=NULL){
                if(node->left->left==NULL&&node->left->right==NULL){
                    cout<<node->data<<" ";
                }
            }
            if(node->right!=NULL){
                if(node->right->left==NULL&&node->right->right==NULL){
                    cout<<node->data<<" ";
                }
            }

            PreOrder2(node->left);
            PreOrder2(node->right);
        }
        else return;
    }

在这里插入图片描述

在这里插入图片描述
方法一:采用递归的做法,很巧妙的思维:

    int getHeight(treenode *root){
        if(root==NULL)return 0;
        int left=getHeight(root->left);
        int right=getHeight(root->right);
        if(left>right)return left+1;
        else return right+1;
    }

简单的来说就是我要求自己这颗子树的高度,我就交给我的孩子去求,先求左孩子再求右孩子,一层一层递归到最底层。
我算出了我的子树的高度之后呢,那么我自己的高度就是左右两颗子树中最大的那一个加一。

方法二:
设定一个最大值,然后每次往下遍历的时候,如果高度大于最大值,则更新最大值:

    void PreOrder(Node *node,int h){
        if(node){
            if(h+1>height)height=h+1;
            PreOrder(node->left,h+1);
            PreOrder(node->right,h+1);
        }
        else return;
    }

在这里插入图片描述
在这里插入图片描述
样例输入
2
AB0C00D00
4 5 3 2 6
ABCD00E000FG00H0I00
9 5 4 11 7 2 8 13 4 1
样例输出
11
27

方法一:
采用和上面类似的方法:

int GetMaxRoad(TreeNode *root){
	if(root==NULL)return 0;
	int left=GetMaxRoad(root->left);
	int right=GetMaxRoad(root->right);
	if(left>right)return root->w+left;
	else return root->w+right;
}

方法二:
在类里面多设一个变量Max,
然后,在遍历的时候,如果加上子结点的权值的时候其值大于Max,则更新Max的值:

void pre(treenode *t,int w){
	if(t){
		if(t->w+w>Max)Max=t->w+w;
		pre(t->left,t->w+w);
		pre(t->right,t->w+w);
	}
	else return;

}

在这里插入图片描述
样例输入
3
ABCDE
ABD##E##C##
ABC##DE####W##F
AB##CDW###E#F##
abc##d
ab##c#d##

样例输出
YES
YES
NO

只需要判断这两种的先序和中序的结果相不相同就可以了,因为先序和中序可以唯一确定一颗二叉树

#include <iostream>
 
using namespace std;
class treenode{
    public:
    char data;
    treenode *left,*right;
    treenode(){
        left=NULL,right=NULL;
    }
};
class tree{
    treenode *root;
    string pre,in,post;
public:
    tree(){}
    void createtree(){
        root=createbitree();
    }
    treenode* createbitree(){
        treenode *t;
        char a;
        cin>>a;
        if(a!='#'){
            t=new treenode();
            t->data=a;
            t->left=createbitree();
            t->right=createbitree();
        }
        else t=NULL;
        return t;
    }
    void preorder1(treenode *t){
        if(t!=NULL){
            pre+=t->data;
            preorder1(t->left);
            preorder1(t->right);
        }
        else return;
    }
    void inorder1(treenode *t){
        if(t!=NULL){
            inorder1(t->left);
            in+=t->data;
            inorder1(t->right);
        }
        else return;
    }
    void postorder1(treenode *t){
        if(t!=NULL){
            postorder1(t->left);
            postorder1(t->right);
            post+=t->data;
        }
        else return;
    }
    void preorder(){
        preorder1(root);
    }
    void inorder(){
        inorder1(root);
    }
    void postorder(){
        postorder1(root);
    }
    string getPre(){return pre;}
    string getIn(){return in;}
    string getPost(){return post;}
 
};
 
void arrayPreOrder(string arrayTree,int i,string &PreOrderTree){
    if(i>=arrayTree.length())return;
    if(arrayTree[i]!='#')PreOrderTree+=arrayTree[i];
    arrayPreOrder(arrayTree,2*i+1,PreOrderTree);
    arrayPreOrder(arrayTree,2*i+2,PreOrderTree);
}
 
void arrayInOrder(string arrayTree,int i,string &InOrderTree){
    if(i>=arrayTree.length())return;
    arrayInOrder(arrayTree,2*i+1,InOrderTree);
    if(arrayTree[i]!='#')InOrderTree+=arrayTree[i];
    arrayInOrder(arrayTree,2*i+2,InOrderTree);
}
 
void arrayPostOrder(string arrayTree,int i,string &PostOrderTree){
    if(i>=arrayTree.length())return;
    arrayPostOrder(arrayTree,2*i+1,PostOrderTree);
    arrayPostOrder(arrayTree,2*i+2,PostOrderTree);
    if(arrayTree[i]!='#')PostOrderTree+=arrayTree[i];
 
}
 
int main()
{
    int t;
    cin>>t;
    while(t--){
        string arrayTree;
        cin>>arrayTree;
        tree tree0;
        tree0.createtree();
        tree0.preorder();
        tree0.inorder();
        tree0.postorder();
        string pretree,intree,posttree;
        pretree=tree0.getPre();
        intree=tree0.getIn();
        posttree=tree0.getPost();
 
        string arrayPre,arrayIn,arrayPost;
        arrayPreOrder(arrayTree,0,arrayPre);
        arrayInOrder(arrayTree,0,arrayIn);
        arrayPostOrder(arrayTree,0,arrayPost);
 
        //cout<<arrayPre<<endl<<arrayIn<<endl<<arrayPost<<endl;
        if(arrayPre==pretree&&intree==arrayIn&&posttree==arrayPost)cout<<"YES"<<endl;
        else cout<<"NO"<<endl;
    }
    return 0;
}

二叉树非递归遍历

这个之后再来补充吧
先附上大佬的博客链接
https://blog.csdn.net/zhangxiangdavaid/article/details/37115355

二叉树的层次遍历

Huffman树

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

这里还需要注意一点,对于兄弟之间,一般来说,在左边的树的权值是会小一点的。看下图可以得知。

在这里插入图片描述
在这里插入图片描述

事实上如果我们没有限制在兄弟中左边小于右边,则画出的树不唯一。
习惯上我们限制左边小于右边

再来一道画huffman树的例题:
首先附上题目和自己书写的过程:
在这里插入图片描述
在画的时候遇到了一些问题:
当画到这里的时候,我们并不清楚是应该将448这棵子树放在第一层右边还是第二层左边?

这个时候我们就先不要把448放进这两个位置,先放一边,然后继续往下画,把8当成是那个最小的加入数组中最小两个的比较范围中。

接下来继续往后,此时便可以确定448应该放在哪里了

在这里插入图片描述

再看下面这个例子 ,在两种情况下,336这个子树被放在了不同的地方
在这里插入图片描述

所以总结就是,对于这种未知的情况,可以先将其放在一边,继续往后写,然后再确定其位置(当然也可以先正常无脑画完,画完后再重新画一次来调整)

代码实现:

在设计Huffman树的结点结构时,考虑到在寻求Huffman编码的过程中,需要多次从叶子结点向根结点回溯,因此采用三叉链表结构

假设叶子结点数为n,从Huffman算法可知(哈夫曼树不应存在度为1的结点,分支结点都是度为2的结点,因为路径要最短)。
Huffman树中的度为0的结点数是n,因此度为2的分支结点数是n-1。
由此可见,Huffman树的存储空间是可以预见的,为2n-1。通常,数组的第一个单元浪费不用,下标从1~2n-1共2n-1个元素。因此分配的空间是2n个
在这里插入图片描述

在这里插入图片描述

class HuffmanTree{
    TreeNode *treenode;
    int num;
public:
    HuffmanTree(int num1){
        num=num1;
        treenode=new TreeNode[2*num];
        for(int i=0;i<2*num;i++){
            treenode[i].parent=0;
        }
        for(int i=1;i<=num;i++){
            cin>>treenode[i].data;
        }
        for(int i=1;i<=num;i++){
            cin>>treenode[i].w;
        }
    }
    void selectMin(int len,int &p1,int &p2){
        int Max=9999;
        int min1=Max,min2=Max;
        //p1=0,p2=0;
        for(int i=1;i<len;i++){
            if(treenode[i].parent==0){
                if(treenode[i].w<min1){
                    min2=min1;
                    p2=p1;
                    min1=treenode[i].w;
                    p1=i;
                }
                else if(treenode[i].w<min2){
                    min2=treenode[i].w;
                    p2=i;
                }
            }
        }
    }
    void createHuffmanTree(){
        for(int i=num+1;i<2*num;i++){
            int p1=0,p2=0;
            selectMin(i,p1,p2);
            treenode[i].left=p1;
            treenode[i].right=p2;
            treenode[p1].parent=i;
            treenode[p2].parent=i;
            treenode[i].w=treenode[p1].w+treenode[p2].w;
        }
    }
};

需要注意的地方,以及自己犯错的地方:
在建树的时候,遍历是需要对从1到2*num-1进行遍历的
在这里插入图片描述
这是因为选取两个最小的加入后,此时我们也需要在父节点中选取最小的进行计算。在这里插入图片描述
并且还不能带等号

在这里插入图片描述
并且p1和p2每次都得重新选取,所以应该设置成放在内部的局部变量:
在这里插入图片描述

注意这三个地方,由于我们每次需要选取最小的,但是开始的时候,num+1-2*num-1这些都是父节点,这些父节点的权值都还是0,那么我们从结点中寻找最小值的时候就不能将其包括进去。
另一方面,我们可以找寻最小值的时候,是不包括len本身的,此处是小于号。
在这里插入图片描述

还需要注意一点的是,我们建树,其实要做的是:

  1. 找到权值最小的两个结点,然后从父节点的第一个位置,也就是num+1开始,我们修改其权值,让它等于子结点两个权值之和
  2. 然后还要修改其左右孩子结点为找到的最小的两个的下标。
  3. 修改孩子的父亲为该父亲。
  4. 需要注意的一点是为了是最终的代码唯一,我们限制死了在兄弟中,小的固定在左子树。

数据结构还有笔试题,在笔试题中我们最好也限制小的在左边而大的在右边,这是为了保证和代码的结果统一。
(虽然说不加这限制也可以,那么就会导致结果不统一。)

因此这里正确的写法为:
在这里插入图片描述

编码
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

需要注意的一点是,我们看图来给字符编码是从根节点到叶子结点,但是编程则是从叶子结点往根走。但是这里的叶子结点全部存储在1-n(包括n)的地方。而父结点全部存储在n+1到2n-1的地方,并且这些结点全部都不含有字符信息,字符全部都在叶子节点上。

注意,这里的编码是指给字符编码,还有另外一种是给你一串字符串,让你加密成数字的情况。

    void HuffmanCode(){
        for(int i=1;i<=num;i++){
            string code="";
            for(int j=i;treenode[j].parent!=0;j=treenode[j].parent){
                if(treenode[treenode[j].parent].left==j)code+='0';
                else code+='1';
            }
            for(int k=code.length()-1;k>=0;k--){
                treenode[i].code+=code[k];
            }
        }
    }

注意:这里循环不要写错了在这里插入图片描述
下面红框的循环应该在上面红框的循环之外。

在这里插入图片描述

译码:给一段字符串,然后让你将其转化成字符

在这里插入图片描述

在这里插入图片描述

    void deCode(string str){
        string stringCode="";
        int root=2*num-1;
        int j=root;
        int outflag=0;
        for(int i=0;i<str.length();i++){
            outflag=0;
            if(str[i]=='0'){
                j=treenode[j].left;
            }
            else if(str[i]=='1'){
                j=treenode[j].right;
            }
            else{
                cout<<"error"<<endl;
                break;
            }
            if(treenode[j].left==0&&treenode[j].right==0){
                outflag=1;
                //outflag代表以及读完了一个字符的编码,此时如果走到了字符串的尽头,则结束循环时就不会判定为错误。但是如果不在读完一个字符的编码时,这时候结束循环,此时outflag会被判定为0,代表不该出去,此时就是出现了字符冗余的情况。
                stringCode+=treenode[j].data;
                j=root;
                //如果找到一个字符,下次再找的时候应该还是从头开始找
            }
        }
        if(outflag==1){
            cout<<stringCode<<endl;
        }
        else cout<<"error"<<endl;
    }

例如
在这里插入图片描述

对特定字符串进行加密:
(例如给定ABC让你编码成01的字符串)

	void StringCode(string str){
        string stringcode="";
        for(int i=0;i<str.length();i++){
            for(int j=1;j<=num;j++){
                if(str[i]==treenode[j].data){
                    stringcode+=treenode[j].code;
                    break;
                }
            }
        }
        cout<<stringcode<<endl;
    }

需要注意一下,内外循环的i不应该相同,
在这里插入图片描述

例题:
在这里插入图片描述
样例输入
2
5 A B C D E
15 4 4 3 2
ABDEC
00000101100
4 A B C D
7 5 2 4
ABAD
1110110

样例输出
A :1
B :010
C :011
D :001
E :000
1010001000011
error!
A :0
B :10
C :110
D :111
0100111
DAC

完整代码:

#include <iostream>

using namespace std;
class TreeNode{
public:
    int parent,left,right;
    int w;
    string code;
    char data;
    Treenode(){
        parent=0,left=0,right=0;
        code="";
    }
};
class HuffmanTree{
    TreeNode *treenode;
    int num;
public:
    HuffmanTree(int num1){
        num=num1;
        treenode=new TreeNode[2*num];
        for(int i=0;i<2*num;i++){
            treenode[i].parent=0;
        }
        for(int i=1;i<=num;i++){
            cin>>treenode[i].data;
        }
        for(int i=1;i<=num;i++){
            cin>>treenode[i].w;
        }
    }
    void selectMin(int len,int &p1,int &p2){
        int Max=9999;
        int min1=Max,min2=Max;
        //p1=0,p2=0;
        for(int i=1;i<len;i++){
            if(treenode[i].parent==0){
                if(treenode[i].w<min1){
                    min2=min1;
                    p2=p1;
                    min1=treenode[i].w;
                    p1=i;
                }
                else if(treenode[i].w<min2){
                    min2=treenode[i].w;
                    p2=i;
                }
            }
        }
    }
    void createHuffmanTree(){
        for(int i=num+1;i<2*num;i++){
            int p1=0,p2=0;
            selectMin(i,p1,p2);
            treenode[i].left=p1;
            treenode[i].right=p2;
            treenode[p1].parent=i;
            treenode[p2].parent=i;
            treenode[i].w=treenode[p1].w+treenode[p2].w;
        }
    }



    void HuffmanCode(){
        for(int i=1;i<=num;i++){
            string code="";
            for(int j=i;treenode[j].parent!=0;j=treenode[j].parent){
                if(treenode[treenode[j].parent].left==j)code+='0';
                else code+='1';
            }
            for(int k=code.length()-1;k>=0;k--){
                treenode[i].code+=code[k];
            }
        }
    }

    void deCode(string str){
        string stringCode="";
        int root=2*num-1;
        int j=root;
        int outflag=0;
        for(int i=0;i<str.length();i++){
            outflag=0;
            if(str[i]=='0'){
                j=treenode[j].left;
            }
            else if(str[i]=='1'){
                j=treenode[j].right;
            }
            else{
                cout<<"error"<<endl;
                break;
            }
            if(treenode[j].left==0&&treenode[j].right==0){
                outflag=1;
                //outflag代表以及读完了一个字符的编码,此时如果走到了字符串的尽头,则结束循环时就不会判定为错误。但是如果不在读完一个字符的编码时,这时候结束循环,此时outflag会被判定为0,代表不该出去,此时就是出现了字符冗余的情况。
                stringCode+=treenode[j].data;
                j=root;
                //如果找到一个字符,下次再找的时候应该还是从头开始找
            }
        }
        if(outflag==1){
            cout<<stringCode<<endl;
        }
        else cout<<"error"<<endl;
    }

	void StringCode(string str){
        string stringcode="";
        for(int i=0;i<str.length();i++){
            for(int j=1;j<=num;j++){
                if(str[i]==treenode[j].data){
                    stringcode+=treenode[j].code;
                    break;
                }
            }
        }
        cout<<stringcode<<endl;
    }

    void display(){
        for(int i=1;i<=num;i++){
            cout<<treenode[i].data<<" :"<<treenode[i].code<<endl;
        }
    }
};
int main()
{
    int t;
    cin>>t;
    while(t--){
        int num;
        cin>>num;
        HuffmanTree tree(num);
        tree.createHuffmanTree();
        tree.HuffmanCode();
        tree.display();
        string code;
        cin>>code;
        tree.StringCode(code);
        string decode;
        cin>>decode;
        tree.deCode(decode);
    }
    return 0;
}

在这里插入图片描述

在这里插入图片描述
样例输入
2
xA00tB00zC00D00
4 7 6 2 3
ab0C00D00
2 10 20
样例输出
34
40

虽然叶子结点的高度无法通过第二题的函数那样求出来,但是叶子结点的父亲的高度是肯定可以求出来的,叶子结点的父亲的高度通过上面那题的GetHeight求出来之后,再-1就可以得到叶子结点所处的高度。
用总高度减去叶子结点的高度就可以得到分支个数。也就是在这里插入图片描述
71中的1,62中的2了。

#include <iostream>
 
using namespace std;
class treenode{
    public:
    char data;
    treenode *left,*right;
    int w;
    treenode(){
        left=NULL,right=NULL;
    }
};
class tree{
    treenode *root;
    int road;
public:
    tree(){road=0;}
    void createtree(){
        root=createbitree();
    }
    treenode* createbitree(){
        treenode *t;
        char a;
        cin>>a;
        if(a!='0'){
            t=new treenode();
            t->data=a;
            t->left=createbitree();
            t->right=createbitree();
        }
        else t=NULL;
        return t;
    }
 
    void preorder1(treenode *t){
        if(t!=NULL){
            if(t->data>='A'&&t->data<='Z'){
                int weight;
                cin>>weight;
                t->w=weight;
                //road+=t->w*getHeight(t);
                //cout<<"w:"<<weight<<" h:"<<getHeight(t)<<" road:"<<road<<endl;
            }
            preorder1(t->left);
            preorder1(t->right);
        }
        else return;
    }
    void preorder2(treenode *t){
        if(t!=NULL){
            if(t->left!=NULL){
                if(t->left->data>='A'&&t->left->data<='Z'){
                    road+=t->left->w*(getHeight(root)-getHeight(t)-1);
                }
            }
            if(t->right!=NULL){
                if(t->right->data>='A'&&t->right->data<='Z'){
                    road+=t->right->w*(getHeight(root)-getHeight(t)-1);
                }
            }
 
            preorder2(t->left);
            preorder2(t->right);
        }
        else return;
    }
    void preorder(){
        preorder1(root);
        //cout<<"1"<<endl;
        preorder2(root);
        //cout<<"2"<<endl;
    }
    int getHeight(treenode *root){
        if(root==NULL)return 0;
        int left=getHeight(root->left);
        int right=getHeight(root->right);
        if(left>right)return left+1;
        else return right+1;
    }
    /*void printMaxRoad(){
        treenode *t=root;
        int sum=0;
        do{
            sum+=t->w;
 
        }while(t->left!=NULL&&t->right!=NULL);
    }*/
 
 
    void printRoad(){
        cout<<road<<endl;
    }
 
 
};
int main()
{
    int t;
    cin>>t;
 
    while(t--){
        tree tree0;
        tree0.createtree();
        int num;
        cin>>num;
        tree0.preorder();
        tree0.printRoad();
    }
    return 0;
}
  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值