ZJU-DS-Chen&He-PTA

统计工龄:

PTA | 程序设计类实验辅助教学平台

#include<stdio.h>
#include<string.h>
#include <unistd.h>
/* 注意 输出的格式没有问题,这里最后一行带了回车也没问题 */
/* 学会如何停住程序, system("pause"), getchar, sleep(unsigned int second);
 */
int main(int argc, char * argv[]){
    int n, i, tmp, tag=0;
    int arr[51];
   
    // 初始化为0
    memset(arr, 0, 51*sizeof(int));

    //input
    scanf("%d", &n);
    if(n < 0){
        return 0;
    }
    for(i=0; i<n; i++){
        scanf(" %d", &tmp);
        arr[tmp]++;
    }

    for(i=0; i<51; i++){
        if(arr[i]!=0){
                if(tag==1){
                    printf("\n");
                }
            printf("%d:%d", i , arr[i]);
            tag = 1;
        }
    }

    //system("pause");
    sleep(2);
    return 0;
}

7-15 PTA Judge

https://pintia.cn/problem-sets/16/problems/677

#include<stdio.h>
/* 留了个坑,没有用归并排序实现表排序
 * 按总分排名,总分相同按完全解决问题个数排序,若是再相同按用户的ID升序来
 * 若用户没有提交 成绩为 -
 * 用户没有提交任何code 不显示
 * 
 */
/* 1.空格的位置 "0 " or " 0"
 * 2.相同的rank排名相同
 * 3.读题不仔细-相同的总分排名相同
 */
#define GET_SCORE(p, i, j, K)  *((int *)p+i*K+j)   //K:问题个数
#define ADD_SCORE(p,i,j, K)  ((int *)p+i*K+j)   //K:问题个数

typedef struct user{
    int ID;
    int sld_pfc;   //完美解决问题的次数
    int score;      //总分
    int normal;     //默认为0; 若能通过编译或提交一次问题即可设为1
}User;

void MergePass(int arr[], int l, int r_start, int r);//留了个坑,没有用归并排序实现表排序
void swap(int *a, int *b);

int main(){
    int N;      //total number of users
    int K;      //total number of problems
    int M;      //total number of submissions
    int FullScore[6];              //,arr[0]先不用; 记录5题的总分
    int i;
    int ID, NewScore, Pnum;         //Pnum题目序号
    User *user;
    int *ptr_s;
    scanf("%d %d %d", &N, &K, &M);                      //input
    user = (User *)malloc(sizeof(User)*(N+1));          //第一个不存数据
    int *Score;
    Score = (int *)malloc((N+1)*K*sizeof(int));         //存放N个用户的K们成绩
    //第i个用户第j门成绩对应Score[i][j-1]     我想要用宏定义替换他
    memset(FullScore, 0, 5*sizeof(int));                //初始化

    for(i=0; i< (N+1)*K; i++){          //初始化
        Score[i] = -2;
    }

    for(i=1; i<=N; i++){
        user[i].ID = i;
        user[i].sld_pfc = 0;
        user[i].score = 0;
        user[i].normal = 0;
    }

    for(i=1; i<=K; i++){
        scanf(" %d", &FullScore[i]);
    }


    for(i=0; i<M; i++){                                 //read submissions
        scanf("%d %d %d", &ID, &Pnum, &NewScore);
        ptr_s = ADD_SCORE(Score,ID, Pnum-1, K);
        if(NewScore > *ptr_s){
            if(user[ID].normal == 0 && NewScore > -1){   //标记正常
                user[ID].normal = 1;
            }

            *ptr_s = NewScore;
            if(NewScore == FullScore[Pnum]){
                user[ID].sld_pfc += 1;                  //更新最大值
            }
        }

    }

    //算总分
    for(i=1; i<=N; i++){
        int j, s=0, tmp_s;
         for(j=0; j<K; j++){
            tmp_s = GET_SCORE(Score, i, j, K);
            if(tmp_s >0){
                s += tmp_s;
            }
         }
         user[i].score = s;
    }


    //开始表排序--要稳定的-插入排序,归并排序
    int *index = (int *)malloc((N+1)*sizeof(int));
    for(i=0; i<=N; i++){
        index[i] = i;
    }

    //按解决问题的数量排序
    int j;
    for(i=1; i<=N; i++){
        for(j=i; j > 1; j--){
            if(user[index[j]].sld_pfc > user[index[j-1]].sld_pfc){
                swap(&index[j], &index[j-1]);
            }
        }
    }
    //按分数排序
    for(i=1; i<=N; i++){
        for(j=i; j > 1; j--){
            if(user[index[j]].score > user[index[j-1]].score){
                swap(&index[j], &index[j-1]);
            }
        }
    }
     int tag = 0, rank=1, pre_s=-1;   /* 与最后一行换行无关 */
     for(i=1; i<=N; i++){
        if(user[index[i]].normal == 1){
            if(tag){
                printf("\n");
            }
            tag = 1;

            if(user[index[i]].score != pre_s){      //总分不重复
                rank = i;

                pre_s = user[index[i]].score;
                printf("%d %05d %d", i, index[i], user[index[i]].score);
            }else{                                  //总分重复

                printf("%d %05d %d", rank, index[i], user[index[i]].score);
            }
        }
        else{
            continue;
        }

        int j, s;
        for(j=0; j<K; j++){     //有正常提交的状态
            s = GET_SCORE(Score, index[i], j, K);
            if(s>=0){
                printf(" %d", s);
            }else if(s==-1){
                printf(" 0");       //NOTe:与 "0 "的区别
            }else{
                printf(" -");
            }

        }
    }


    free(user);
    free(Score);
    free(index);

    return 0;
}

void swap(int *a, int *b){
    int t;
    t = *a ;
    *a = *b;
    *b = t;
}

7-16 Sort with Swap(0, i) (25 分)

PTA | 程序设计类实验辅助教学平台

v1.模拟对物理元素进行交换                                                  ==>fail

根据轮换关系逐项交换index[],直到index[]的顺序为0,1,2,...在增加一个数组circle记录它们的数值。结果发现行不通,我需要关键性的是0.1.2他们的下标,而不是他们的值;人很容易根据值将他们排列,而机器不行,需要指导他们的下标才能将其对换。

 v2.发现不用交换,只需要找出所有多元环中元素的个数        ==>存在可以优化的地方

多元环ri(i0,1,2,...),记多元环中的元素个数为ni;        若含0的多元环比较次数为 ni-1, 不含0的多元环对换次数为ni+1 (这里我自己搞错了,曾以为是ni, 其实是1+ ni-1 +1),则总共对换次数分情况讨论:

        i)含0, n1+n2+..+nk-2;       

        ii)所有环都不含零,   n1+n2+..+nk;        

 v3.  发现只需要找出多元环中单环和多环的个数                  ==>已优化

        i)若含0, total = n-S+K-2;

        ii)所有环都不含0, total = n-S+K;

v3的好处体现在不用排序,v1,v2需要排序,我没有意识到居然不用排序也可以找出轮换的圈圈.

逐步求精,原来算法不是简单的要你去模拟过程,而是抽象出它的性质,能否直接从状态推出过程,用过程找过程的方法属于较低水平,而用状态推过程就比较需要对问题进行深入理解和探索。

/* 这是一个数学题,离散数学的中轮换用交换替代
 */
#include <stdio.h>
#include <stdlib.h>
int swap(int* a, int *b);

int main(int argc, char *argv[]){
    int n, arr[100000], visit[100000];  //circle is used to stored the sequence of ring 1 2 3..
    int i, cnt=0, j;
    memset(arr, 0, sizeof(int)*100000);
    memset(visit, 0, sizeof(int)*100000);
    int S=0;    //记录单环个数
    int K=0;    //记录多环个数
    //input
    scanf("%d", &n);
    for(i=0; i<n; i++){
        scanf(" %d", &arr[i]);

    }
    int tag=0;
    if(arr[0] != 0){  //在圈内
        tag=1;
    }

    int p;
    for(i=0; i<n; i++){
        p = i;
        if(arr[p] == p){
            S++;
            continue;
        }
        if(arr[p]!=i && visit[p] == 0){    //ring没有指向开头元素==>没有结束, visit代表没有访问过
            K++;
            while(arr[p]!=i && visit[p] == 0){
                visit[p] = 1;
                p = arr[p];

            }

            visit[p] = 1;   //ring的最后一个元素,需要拿出来处理

            //cnt++;      //不含0的环,交换次数为环的长度+1
        }
    }
    if(tag){
        cnt = n-S+K-2;
    }else{
        cnt = n-S+K;
    }
    printf("%d", cnt);
    //system("pause");
    return 0;
}

int swap(int* a, int *b){
    int t;
    t = *a;
    *a = *b;
    *b = t;
}

03-tree traversals again        

难度:中等         

耗时:4H(at least)include看小白专场后的.(看小白专场前花了2小时自己摸索==> failure ==> 我太菜了)

PTA | 程序设计类实验辅助教学平台

不会使用c++模板的我只能自力更生写栈的模板,我本来窃喜自己会将栈单独放到一个头文件,后来发现PTA online只允许一个文件,所以就把stack_int的代码复制过来了.

v1. 建树(troublesome)

 通过非递归的中序遍历可以推出树的结构。奇妙在于用非递归的方法可以知道书的前序排列---push入栈的顺序. 怪不得陈姥姥说这一道题考了树的三种遍历

具体实现:   

                方法1:借用堆栈在模拟一遍它的过程,从而构建树

                方法2. 不接用堆栈,借用复杂的结构(静态链表)构建树. 

                          五元组:    | data | tag | lc | rc | parent |

datataglcrcparent

        用这种方法关键 tag记录树的访问状态, status: 0,1,2,3; 但是我没能去实现,因为有点复杂也有点费时间. 话又说回来,这其实也可以被视是一种'堆栈'

                

v2. 不建树, 前,中,后 知二求一(必须包含中序哟!这是一种比较巧妙的方法),通过递归的方法,我能够感受到递归的巧妙与它的能力。

递归的威力.

pre[], in[], post[] 分别存放某棵树的前序、中序和后续遍历的序列。 pre_i, in_i, post_i分别表示前、中和后序的序列里该(子)树开始的下标位置, n表示该序列的个数.

递归思路:

1.先通过前序序列在pre[]中找出root;

2.找到root所在中序遍历序列中的位置即可将该树划分为左右子树,因此就可以递归的求解.

Note: 注意递归的推出条件,还有别忘了每次递归中对root的处理(赋给post).

#include<stdio.h>
#include<string.h>
#include<stdlib.h>

#define N 100
/* 通过自己的头文件进行入栈操作
 *    通过递归的方法去还原后序序列而不是建树,因为建树太麻烦了
 *
 *
 * step: 1. build pre[], in[]
 *      2. fill the post[]  in recursive way

*/
typedef struct {
    int arr[N];
    int top;

}stackint;
typedef stackint* STACKINT;

STACKINT Init_int();
int IsEmpty_int(STACKINT S);
int IsFull_int(STACKINT S);
int Push_int(STACKINT S, int c);
int GetTop_int(STACKINT S);
int Pop_int(STACKINT S);



int read(int n, int pre[], int in[]);
void print(int arr[], int n);
void solve(int pre[], int in[], int post[], int pre_i, int in_i, int post_i, int n);
int main(){
    int n;

    int pre[N], in[N], post[N];
    // clean the space
    memset(pre, 0, sizeof(int)*N);


    scanf("%d\n", &n);
    read(n, pre, in);
    solve(pre, in, post, 0, 0, 0, n);

    /*
    print(pre, n);
    print(in, n);
    */
    print(post, n);


    return 0;
}

int read(int n, int pre[], int in[]){
    STACKINT s = Init_int();
    char buff[30] = {'0'};
    int i, pre_i=0, in_i=0;
    for(i=0; i < 2 * n; i++){
        //scanf("%s ", buff);
        gets( buff );
        int len = strlen( buff );
        if( len == 3 ) { // is pop{
            int num = Pop_int( s );
            in[in_i++] = num;
        }else{  // is Push
            char *ptrnum = &buff[5];
            int num = atoi( ptrnum );
            pre[pre_i++] = num;
            Push_int(s, num);
        }
    }
}

void print(int arr[], int n){
    int i;
    if( n <= 0){
        return ;
    }
    for(i=0; i<n-1; i++){
        printf("%d ", arr[i]);
    }
    printf("%d", arr[i]);
    //printf("\n");
}


/**
 *
 *
 * parameter: pre_i, in_i, post_i is the start index of the pre[]array, in[]array, post[]array
 *              n : the length of the sequcences
 **/
void solve(int pre[], int in[], int post[], int pre_i, int in_i, int post_i, int n){
    int root, i;
    root = pre[ pre_i ];
    if( n == 0 ){
        return ;
    }
    if( n == 1){
        post[post_i] = pre[pre_i];
        return ;
    }
    // write the root value to the post array
    post[post_i+n-1] = root;


    //find the postion of root in the in[] array
    for(i = in_i ; i < in_i + n ; i++){
        if( in[i] == root ){
            break;
        }
    }

    int L;  // the numbers of nodes in the lefe subtree
    int R;  //the numbers of nodes in the right subree
    L = i - in_i;
    R = n - 1 - L;

    // build the left tree by recursively
    solve(pre, in, post, pre_i+1, in_i, post_i, L);
    solve(pre, in, post, pre_i+1+L, in_i+1+L, post_i+L, R);
}

STACKINT Init_int() {
    STACKINT s = (STACKINT)malloc(sizeof(stackint));
    if (s == NULL) {
        printf("Out of Memory!\n");
        exit(1);
    }
    s->top = -1;
    memset(s->arr, 0, N * sizeof(int));
    return s;
}
int IsEmpty_int(STACKINT S) {
    if (S->top == -1) {
        return 1;
    }
    return 0;
}
int IsFull_int(STACKINT S) {
    if (S->top == N - 1) {
        return 1;
    }
    return 0;
}

int Push_int(STACKINT S, int c) {
    if (IsFull_int(S)) {
        printf("Push_int Error! Stack is full!\n");
        return 0;
    }

    S->arr[++(S->top)] = c;     /* BIG mistake : s->top++ */

    return 1;
}
int Pop_int(STACKINT S) {
    if (IsEmpty_int(S)) {
        printf("Pop_int Error! Stack is empty!\n");
        exit(1);
    }
    return S->arr[S->top--];
}
int GetTop_int(STACKINT S) {
    if (IsEmpty_int(S)) {
        printf("GetTop_int Error! STACKINT is empty\n");
        exit(1);
    }
    return S->arr[S->top];
}

04-tree3是否为同一颗二叉搜索树

PTA | 程序设计类实验辅助教学平台

难度: 简单

耗时: 3h

[分析]

法1:(基于过程) 建树,模拟BST建立过程

法2:不建树. 通过按某种规则排列插入序列,若某两个插入序列对应的BST相同,那么经过调整后它们序列一定相同. E.g.  2 1 3 和 2 3 1, 规则:根左右, 都可以换成 2 1 3. 所以该方法性的通. 基于递归的方法,自顶向下进行调整.(受tree traversals again 的启发)

法3:先建立一个树----t1,然后通过遍历该树t1,能否和插入顺序相匹配. 关键在于如何通过插入顺序和一颗树来判断他们是否匹配.

[反思,收获]

        1.自己对数组(树)调整时 buff[] 中忘记写数字,调试才检查出错误; 之前还因为如此会以为按二叉搜索树的插入序列可以递归的调整数组结构为  | 根 | 左子树 | 右子树 |. 如此,多个插入顺序可以对应同一棵树, 而它们同时也对应同一种序列(经过根左右顺序调整后). 

        2.C语言中 scanf(" %d", &tmp); '%' 前面加空格可以跳过空白字符

[code] 采用法2----简单呀!(toulan)

/**
 * thinking 1:
 * 1. built a tree in what store structure?
 * 2. Get inorder travsersal sequences of the tree
 * 3. Compare
 *
 * thinking 2:  ==> fail
 * 展开一颗树,如果它们序列相同则相同 <==> 中序序列和BST一一对应
 *
 * thinking 3: ==> 按root大小分左右子树
 */

 #include<stdio.h>


void myread(int dst[], int n);     //convert the input sequence into the arrary: dst[]
void BSTadjust(int tree[], int start, int n);
int IsSameBST(int t1[], int t2[], int n);


int main(){
    int origin[30] = { 0 };
    int newtree[30] = { 0 };
    int i, boundry, group;

    do
    {
        scanf("%d", &boundry);
        //c = getchar();
        if( boundry == 0 ){
            break;
        }
        scanf(" %d", &group);
        //getchar();

        myread(origin, boundry);
        BSTadjust(origin, 0, boundry);
        //print( origin, boundry );

        for( i = 0; i < group; i++ ){
            myread( newtree, boundry );
            //print( newtree, boundry);

            BSTadjust( newtree, 0, boundry);
             if ( IsSameBST( origin, newtree, boundry ) ){
                printf("Yes\n");
             }else{
                printf("No\n");
             }


        }
    }while(1);

    return 0;
 }

 /**
  * convert input into a array whose length is n
  * parameter: dst[], n
  */
void myread(int dst[], int n){
   int i;
   for(i=0; i<n; i++){
        scanf(" %d", &dst[i]);
        //getchar();
   }
}

/**
 * arrange tree as the sequence that root, lc, rc by recursively
 *
 */
void BSTadjust(int tree[], int start, int n){
    int i, j, L, R;
    int root = tree[start];
    int buff[30] = { 0 };


    //递归出口
    if( n==0 || n==1 ){
        return ;
    }



    // forget to handle the root node
    j = 0;
    buff[j++] = root;


    //先记录左子树
    L=0;
    for(i = start; i < start + n; i++){
        if( tree[i] < root ){
            L++;
            buff[j++] = tree[i];
        }
    }
    //在记录右子树
    R = 0;
    for(i = start; i < start + n; i++){
        if( tree[i] > root ){
            R++;
            buff[j++] = tree[i];
        }
    }

    //倒回到原tree[]数组
    j=0;
    for(i = start; i < start + n; i++){
            tree[i] = buff[j++];

    }

    BSTadjust( tree, start+1, L);
    BSTadjust( tree, start+1+L, R);
}

/**
 * function: judge the elements of 2 arrays , whether they are same or not
 */
int IsSameBST(int t1[], int t2[], int n){
    int i;
    for( i=0; i<n; i++){
        if( t1[i] != t2[i]){
            return 0;
        }
    }
    return 1;
}

04-tree complete binary search tree

PTA | 程序设计类实验辅助教学平台

难度: 简单

时间:1.5h

 一看到完全二叉树: 我就想到了数组作为其存储结构,再加上BST的中序遍历是递增序列,所以我想再拿一个数组tree[]来记录树信息,先将节点关键value排序,然后从根(tree[0])开始将递增序列中的值按照中序遍历顺序写入tree. 需要一个全局变量记录增序序列的下标.

[反思,收获]递归是一个好用的武器,在本章的习题中我能够不建树就不建树.


/*
 * 既要是BST, 有要是完全二叉树
 * 一旦是完全二叉树,就可以用数组存放
 * 中序遍历恰好的数组的stride 为1 的顺序遍历
 */
 #include<stdio.h>
#include<math.h>
 void myread(int arr[], int n);
 void mysort(int arr[], int n);
 void Inorder(int arr[], int n, int  root, int tree[]);
 void myprint(int arr[], int n);
static int cnt=0;   // be originated only once

 int main(){
    int n;
    int arr[10000] = { 0 };
    int tree[1000] = { 0 };
    scanf("%d", &n);
    myread(arr, n);
    //myprint(arr, n);
    mysort(arr, n);
    //myprint(arr, n);

    Inorder(arr, n, 0, tree);    //将arr数组中的增序序列按中序遍历方式写入tree
    myprint(tree, n);
    return 0;
 }

 /** function: read data into array whose length is n
  *
  */
 void myread(int arr[], int n){
    int i;
    for(i=0; i<n; i++){
        scanf(" %d", &arr[i]);
    }
 }

 /** function: sort
  */
void mysort(int arr[], int n){
    int i, j;
    int min_pos;
    for( i=0; i<n-1; i++){
        min_pos = i;
        for(j=i+1; j < n; j++){
            if( arr[j] < arr[min_pos] ){
                min_pos = j;
            }
        }
        int tmp = arr[i];
        arr[i] = arr[min_pos];
        arr[min_pos] = tmp;
    }
}


/** function: 中序遍历的同时按从小到大的顺序将数组元素写入树中
 *  parameter: arr[], n, root, tree
 */

void Inorder(int arr[], int n, int root, int tree[]){


    if( 0 <= root && root <= n-1 ){
        Inorder(arr, n, root*2+1, tree); // go to left subtree
        tree[ root ] = arr[ cnt++ ]  ;
        Inorder(arr, n, root*2+2, tree);    // go to right subtree
    }
}

/** function:
 */
 void myprint(int arr[], int n){
    int i;
    if(n<1) return ;
    for(i=0; i<n-1; i++){
        printf("%d ", arr[i]);
    }
    printf("%d", arr[i]);
 }

04-tree-the root of AVL

难度: 中等偏难

时间: 4h+

​​​​​​PTA | 程序设计类实验辅助教学平台

麻烦的地方在于自己无从下手,如何去构建AVL. 还想到检测平衡因子时需要递归测得高度,导致时间复杂性太高,觉得这个太难了. 后来综合了几位的code,决定用height域记录高度,方便测出高度.

思路:根据自己的结构在纸上写出具体的伪操作,再 coding 以理清自己的思路。这个(c语言)充分利用递归的思想和遍历的思想,让父节点和子节点之间传递信息.

If I were a teacher:

我会先让学生先进行简单的例子模拟 ==> 发现一些性质(LR可以由两次简单旋转取代) ==> 选择合适的数据结构和方法(递归) ==> 突破主要问题: insert2AVL 函数(进行分析:如何插入,如何检测出失衡,如何调整) ==> 检测debug 和检查(根据所选的数据结构 去 检查 不同情况下的操作是否完整) ==> summary 

/*
 * 找root
 * 肉眼容易看出来转换顺序,但是如何利用计算机呢?
 * 我去模拟一遍?难度很大,而且他的复杂度为o(n).
 * 解决方案:通过画图理清细节.
 * 重点在insert2AVL, 插入需要递归的遍历,每次交换子树的高度信息(自底向上)
 * 若不需要旋转则调整高度,否则旋转中会自动调整高度
 */
#include<stdio.h>
#include<stdlib.h>
/**
 *  data:2022/5/7
 *  structure: 通过设置一个height域 方便记录各子树的高度
 *  ways: 采用递归的方法,自底向上传递树的高度变化
 *  properties: LR and RL can be replace by 2 singleRotate
 *  多看看别人的code提供了交流的渠道or新的视野
 */
typedef struct AVLnode{
    int data;
    int height;
    struct AVLnode* lc;
    struct AVLnode* rc;
}*AVLTree;

typedef int ElementType;
//typedef struct AVLnode* AVLTree;

AVLTree Insert2AVL(AVLTree p, ElementType x );
AVLTree SingleLeftRotate(AVLTree p);
AVLTree SingleRightRotate(AVLTree p);
AVLTree LR_Rotate(AVLTree p); // right rotation first, then rotate the lfet
AVLTree RL_Rotate(AVLTree p); // left rotation first, then rotate the right
int GetHeight(AVLTree p);   // get height by recursive traversal
void UpdateHeight(AVLTree p);   // update the height region of a node
int Max(int a, int b);

int main(){
    AVLTree t=NULL;
    int i, n, tmp;
    scanf(" %d", &n);
    for(i=0; i<n; i++){
        scanf(" %d", &tmp);
        t = Insert2AVL(t, tmp);
    }
    //if not have "if", t is NULL, which caused Error!
    if(t){
        printf("%d", t->data);
    }
    return 0;
}

/** get the bigger one of 2 number
 */
int Max(int a, int b){
    if(a>b){
        return a;
    }
    return b;
}

/** get the height of a AVL
 *  利用 height 域更新高度,而不是递归
 *  前提:子树的高度都是可靠的
 */
int GetHeight(AVLTree p){
    // 递归出口
    if( p ==  NULL){
        return 0;
    }
    int lh; // height of lc
    int rh; // height of rc
    /*
    lh = GetHeight(p->lc);
    rh = GetHeight(p->rc);
    */
    if(p->lc == NULL)
        lh = 0;
    else
        lh = p->lc->height;


    if(p->rc != NULL)
        rh = p->rc->height;
    else
        rh = 0;

    return Max(lh, rh)+1;
}

/** update the height of a node
 */
 void UpdateHeight(AVLTree p){
     p->height = GetHeight(p);
 }

/**
 * single left Rotate
 *  LL旋转
 */
AVLTree SingleLeftRotate(AVLTree p){
    AVLTree old_root = p;
    AVLTree new_root = old_root->lc;

    old_root->lc = new_root->rc;
    new_root->rc = old_root;

    UpdateHeight(old_root);
    UpdateHeight(new_root);
    return new_root;
}

/**
 * SingleRightRotate
 * RR旋转
 * 类似LLrotate
 */
 AVLTree SingleRightRotate(AVLTree p){
     AVLTree old_root = p;
     AVLTree new_root = p->rc;

     old_root->rc =  new_root->lc ;
     new_root->lc = old_root;

    UpdateHeight(old_root);
    UpdateHeight(new_root);
    return new_root;
 }

/**
 * LR_Rotate 左右旋转 先右旋再左旋哦!
 *  巧妙之处:可以用两次单旋的完成
 */
AVLTree LR_Rotate(AVLTree p){
    AVLTree old_root = p;
    AVLTree new_root = SingleRightRotate(old_root->lc);

    old_root->lc = new_root;    //还原进行一次右旋调整后的AVL结构

    new_root = SingleLeftRotate(old_root);
    return new_root;

}

/**
 * RL_Rotate 右左旋转 先左后右
 *  同上  LR_Rotate
 *  巧妙之处:可以用两次单旋的完成
 */
AVLTree RL_Rotate(AVLTree p){
    AVLTree old_root  = p;
    AVLTree new_root = SingleLeftRotate(old_root->rc);

    old_root->rc = new_root;
    new_root = SingleRightRotate(old_root);
    return new_root;
}

/**
 *  insert a element into a AVL
 *  return: the root of AVL that after being adjusted
 *  recursively thinking
 *  最重要的一个函数
 */
AVLTree Insert2AVL(AVLTree p, ElementType x){
    // 递归出口
    if(p == NULL){
        p = (AVLTree) malloc(sizeof(struct AVLnode));
        if(p == NULL){
            printf("Out of Memory!\n");
            exit(1);
        }
        p->lc = p->rc = NULL;
        p->data = x;
        p->height = 1;
        return p;
    }
    //递归基
    if(x < p->data ){       //go into lc
        AVLTree new_lc;
        new_lc = Insert2AVL( p->lc, x);
        p->lc = new_lc;     //重复工作 对于没有改变的节点, 只是新插入节点需要这样,这里可以用C++的引用优化

        // judge if the subtree have been broken
        AVLTree new_root;
        if(GetHeight(p->lc) - GetHeight(p->rc) > 1){
            //判断LL类型, 有两种方法. 1.看左子树的lc,rc的高度差; 2.看X值, x比左子树的值大还是小
            if(GetHeight(p->lc->lc) > GetHeight(p->lc->rc) ){
                    new_root =  SingleLeftRotate(p);

            }else{  //LR型
                    new_root = LR_Rotate(p);
            }
            return new_root;

        }
        //加入节点后不需要调整 ==> 更改高度
        else{
            UpdateHeight(p);
            return p;
        }

    }else if(x > p->data){  //go into rc
        AVLTree new_rc;
        new_rc = Insert2AVL( p->rc, x);
        p->rc = new_rc;     //建立链接

        AVLTree new_root;
        if( GetHeight(p->rc) - GetHeight(p->lc) > 1){
            // AVL失衡,需要进行调整
            if(GetHeight(p->rc->lc) > GetHeight(p->rc->rc)){
                //为RL typed
                new_root = RL_Rotate(p);
            }else{
                //RR
                new_root = SingleRightRotate(p);
            }
            //旋转的过程中包括修改height 域
            return new_root;
        }
        // 没有引起失衡
        else{
            UpdateHeight(p);
            return p;
        }
    }

    // return paretn directly if there is already x in the AVL
    printf("Element %d already exsitsed in the AVL\n", x);
    exit(1);

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值