问题求解lab5

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

#define N 10000
typedef struct RB{
    /* data */
    int val;
    struct RB *left;
    struct RB *right;
    //红色是1 黑色0
    int color;
    struct RB *parent;
}RB;
RB* root;
int sum = 0;
int sum_node = 0;
void leftRotate(RB *p){
    if(p != NULL){
        //记录p的右儿子
        RB *rightkid = p->right;
        //1.空出右儿子的左子树
        p->right = rightkid->left;
        //左子树不为空,需要更新父节点
        if(rightkid->left!= NULL){
            rightkid->left->parent = p;
        }
        //空出p的父节点
        rightkid->parent = p->parent;
        //父节点指向右儿子
        if(p->parent == NULL){
            //如果p是根节点
            root = rightkid;
        }
        else if(p == p->parent->left){
            //如果p在左边
            //右儿子成为父节点的左儿子
            p->parent->left= rightkid;
        }
        else{
            p->parent->right = rightkid;
        }
        // 3.右儿子和节点p会师,节点p成为左子树
        rightkid->left = p;
        p->parent = rightkid;
    }
}

void rightRotate(RB *p){
    if(p != NULL){
        //记录p的左儿子
        RB *leftkid = p->left;
        //1.空出p的左儿子的右子树
        p->left = leftkid->right;
        //右子树不为空,则更新他的父节点
        if(leftkid->right != NULL){
            leftkid->right->parent = p;
        }
        //2.空出节点p的父节点
        leftkid->parent = p->parent;
        //父节点指向左儿子
        if(p->parent == NULL){
            root = leftkid;
        }
        else if(p->parent->left == p){
            //如果是左儿子
            p->parent->left = leftkid;
        }
        else{
            p->parent->right = leftkid;
        }
        //3.顺利会师
        leftkid->right = p;
        p->parent = leftkid;
    }
}

//插入结点x
void insert(RB *x){
    RB *parent = NULL;
    RB *cur = root;
    while(cur!= NULL){
        if(cur->val == x->val){
            return;
        }
        else if(cur->val > x->val){
            parent = cur;
            cur = cur->left;
            if(cur == NULL) break;
        }
        else{
            parent = cur;
            cur = cur->right;
            if(cur == NULL) break;
        }
    }
    if(parent != NULL){
        if (parent->val > x->val) {
            parent->left = x;
        } else {
            parent->right = x;
        }
    }
    x->parent = parent;
}

RB *parentOf(RB* p){
    return (p == NULL?NULL:p->parent);
}

void FixAfterInsert(RB *x){
    insert(x);
    //默认1是红色 黑0
    x->color = 1;
    ///如果没有父亲 或者是父节点是黑色 则不需要调整 直接返回
    if(x->parent == NULL) return;
    if(x->parent->color == 0) return;
    //P不为空,不是整棵树的根节点,父亲为红色,需要调整
    while(x != root && x->parent->color == 1){
        //父亲是祖父的左儿子
        if(parentOf(x) == parentOf(parentOf(x))->left){
            RB *uncle = parentOf(parentOf(x))->right;
            //父亲和叔叔都是红色
            if(uncle != NULL && uncle->color == 1){
                //父亲和叔叔都变成黑色
                parentOf(x)->color = 0;
                uncle->color = 0;
                //祖父变成红色,继续从祖父开始调整
                parentOf(parentOf(x))->color = 1;
                x = parentOf(parentOf(x));
            }
            //叔叔是黑色
            //叔父异色,自己是左儿子,进行R操作
            //叔父异色,自己是右儿子,父亲成为新的X,
            //对父亲执行左旋,在执行右旋
            ///叔叔结点是null的话 默认为黑色结点
            else{
                //自己是父亲的右儿子,需要对父亲左旋
                if(x == parentOf(x)->right){
                    x = parentOf(x);
                    leftRotate(x);
                }
                //自己是父亲的左儿子,变色后右旋
                parentOf(x)->color = 0;
                parentOf(parentOf(x))->color = 1;
                rightRotate(parentOf(parentOf(x)));
            }
        }
        ///父亲是祖父的右儿子
        else{
            RB *uncle = (parentOf(parentOf(x))->left);
            //父叔同为红色,只需要进行颜色调整
            if(uncle != NULL && uncle->color == 1){
                //叔父都变成黑色
                parentOf(x)->color = 0;
                uncle->color = 0;
                //祖父变为红色,从祖父开始调整
                parentOf(parentOf(x))->color = 1;
                x = parentOf(parentOf(x));
            }
            //叔父异色,自己是左儿子,进行RL操作
            //自己是右儿子,进行L操作
            else{
                if(parentOf(x)->left == x){
                    x = parentOf(x);
                    rightRotate(x);
                }
                //自己是父亲的右儿子,变色后左旋
                parentOf(x)->color = 0;
                parentOf(parentOf(x))->color = 1;
                leftRotate(parentOf(parentOf(x)));
            }
        }
    }
    //最后将根节点置为黑色
    root->color = 0;
}

void show(RB *p){
    if(NULL == p){
        sum_node++;
        return;
    }
    //printf("%d:%d\n",p->val,p->color);
    show(p->left);
    show(p->right);
    if(p->color == 1) sum++;
    sum_node++;
}

int main(){
    int num = 0;
    while(num++<100){
        RB *p = (RB*) malloc(sizeof (RB)*N);
        srand((unsigned)time(0));
        for(int i = 0;i < N;i++){
            p[i].val = 1.0*rand()/RAND_MAX*N;
            //printf("val is:%d\n",p[i].val);
            //待插入的点的颜色为红色
            p[i].color = 1;
            p[i].left = NULL;
            p[i].right = NULL;
            p[i].parent = NULL;
        }
        root = &p[0];
        p[0].color = 0;
        for(int i = 1;i<N;i++){
            FixAfterInsert(&p[i]);
        }
        show(root);
        free(p);
    }
    printf("N值:%d\n红节点个数:%d,总节点(包含黑节点):%d\n",N,sum/100,sum_node/100);
    printf("红节点占比:%.2f%c",(double)(sum/100)/(sum_node/100)*100,'%');
    return 0;
}

在红黑树插入新节点后的调整中出了比较大的问题,主要是当新插入的节点没有叔叔节点时如何处理,上网查了很多资料才发现是要把“不存在的叔叔节点”当作黑节点来处理,这样一来红黑树的建立就得到了解决。

第二个问题是遍历问题,一开始发现N值扩大10倍,相应的红节点个数也扩大10倍,后来发现N越大,红节点个数反而不增加了。我和xyb同学讨论了一下,他认为是随机数的重复问题,导致出现相同的值的时候我的程序没有插入该节点。所以我又增加了sum_node来判断实际的节点个数,这里把空的nil节点也算进去了。随着N值增加,红节点占比保持在24.3%左右。

其实还是不太明白在产生随机数的过程中为什么会出现这么多重复的数字。或者说红节点个数的增长缓慢的并不是由于随机数的重复造成的,而是由其他因素造成的。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
Matter Lab 是一个开源的 JavaScript 库,用于科学计算和数据可视化。它包含了许多数学和科学计算中常用的算法和工具,其中也包括了求解线性方程组的高斯-赛德尔迭代法。 在 Matter Lab 中,可以使用以下代码来求解形如Ax=b的线性方程组: ```javascript const { Matrix, LUDecomposition } = require('mathjs') // 求解Ax=b,其中A为系数矩阵,b为常数向量 function gaussSeidel(A, b, maxIter = 1000, tol = 1e-6) { const n = A.size()[0] let x = Matrix.zeros(n, 1) let D = Matrix.diag(A.diag()) let L = Matrix.zeros(n, n) let U = Matrix.zeros(n, n) // 分解A为D-L-U for (let i = 0; i < n; i++) { for (let j = 0; j < n; j++) { if (i < j) { U.set([i, j], A.get([i, j])) } else if (i > j) { L.set([i, j], A.get([i, j])) } } } // 迭代求解 for (let iter = 0; iter < maxIter; iter++) { let x0 = x.clone() for (let i = 0; i < n; i++) { let sum1 = 0 let sum2 = 0 for (let j = 0; j < i; j++) { sum1 += L.get([i, j]) * x.get([j, 0]) } for (let j = i + 1; j < n; j++) { sum2 += U.get([i, j]) * x0.get([j, 0]) } x.set([i, 0], (b.get([i, 0]) - sum1 - sum2) / D.get([i, i])) } if (x0.sub(x).norm() < tol) { break } } return x } // 示例 const A = Matrix([ [4, -1, 0], [-1, 4, -1], [0, -1, 4] ]) const b = Matrix([[1], [0], [1]]) const x = gaussSeidel(A, b) console.log(x.toString()) ``` 在上面的代码中,我们使用了 mathjs 库中的 Matrix 类来表示矩阵,并使用 LUDecomposition 类来进行矩阵分解。具体来说,我们首先将系数矩阵A分解为D-L-U的形式,然后根据高斯-赛德尔迭代公式进行迭代求解。当两次迭代的解之差小于给定的容差tol时,迭代停止并返回解x。 需要注意的是,高斯-赛德尔迭代法并不一定收敛,因此在实际使用中需要进行收敛性的分析,并可能需要使用其他的求解方法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

X.lmy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值