二叉树的那些事

一篇关于二叉树的笔记。

  • 广义表生成二叉树。
  • 二叉树前、中、后序遍历递归实现。
  • 二叉树前、中、后序遍历非递归实现。
  • 二叉树层次遍历
  • 二叉排序树(二叉搜索树)生成
  • 中序线索二叉树声生成、遍历。

 

//
//  main.cpp
//  二叉树前中后缀遍历之递归和非递归、层次遍历、中序线索二叉树建立、遍历
//
//  Created by scnulpc on 2018/10/16.
//  Copyright © 2018年 scnulpc. All rights reserved.
//

#include <iostream>
#include <stack>
#include <queue>
using namespace std;
struct treeNode
{
    char value;
    int ltag;
    int rtag;
    treeNode* left;
    treeNode* right;
    treeNode(char a):value(a),ltag(0),rtag(0),left(NULL),right(NULL){}
};
struct node
{
    int value;
    node *left,*right;
    node(int a):value(a),left(NULL),right(NULL){};
};
//广义表生成二叉树-非递归
treeNode* createTreeByList(char end)
{
    char ch;
    treeNode* root=NULL,* pre = NULL,*temp;
    stack<treeNode*> *s = new stack<treeNode*>();
    cin>>ch;
    int flag=2;
    while (true)
    {
        if (ch==end) break;
        switch (ch) {
            case '(':flag=0;s->push(pre);break;
            case ',':flag=1;break;
            case ')':flag=2;s->pop();break;
            default:
                if (flag==0)//'('
                { temp=s->top(); temp->left=new treeNode(ch);pre=temp->left;}
                else if(flag==1)//','
                {temp=s->top();temp->right=new treeNode(ch);pre=temp->right;}
                else if (flag==2)//')'
                {
                    if (root==NULL) {root=new treeNode(ch);pre=root;}
                }
                break;
        }
        cin>>ch;
    }
    return root;
}

//前序遍历-递归
void preOrder(treeNode*p)
{
    if (p==NULL) return;
    cout<<p->value<<" ";
    preOrder(p->left);
    preOrder(p->right);
}
//前序遍历-非递归
void preOrderND(treeNode*p)
{
    stack<treeNode*> s;
    s.push(p);
    treeNode* temp;
    while (!s.empty())
    {
        temp=s.top();
        s.pop();
        cout<<temp->value<<" ";
        if (temp->right!=NULL) s.push(temp->right);
        if (temp->left!=NULL) s.push(temp->left);
    }
    cout<<endl;
}
//中序遍历-递归
void midOeder(treeNode* p)
{
    if (p==NULL) return;
    midOeder(p->left);
    cout<<p->value<<" ";
    midOeder(p->right);
}
//中序遍历-非递归
//对于每个结点,先将最左子孙(如果存在的话),然后再次最左子孙,再次之
void midOrderND(treeNode*p)
{
    if (p==NULL) return;
    stack<treeNode*> s;
    treeNode* current = p;
    
    while ((!s.empty())||current!=NULL)
    {
        if (current!=NULL) {
            s.push(current);
            current=current->left;
        }
        else
        {
            current=s.top();
            s.pop();
            cout<<current->value<<" ";
            current=current->right;
        }
    }
    cout<<endl;
    
}
//后缀遍历-递归
void sufixOrder(treeNode* p)
{
    if (p==NULL) return;
    sufixOrder(p->left);
    sufixOrder(p->right);
    cout<<p->value<<" ";
}
//后缀遍历-非递归
//对于一个结点,先把它的左子树输出,回到它自己,再把它的右子树输出,再回到它自己,这时可以把它自己输出了
void sufixOrderND(treeNode* p)
{
    stack<treeNode*> s;
    int flag=0;         //flag:0 表示从左子树中返回。 flag:1 表示从右子树中返回
    //int move=1;         //move:1 一棵子树还没生成。 move:0 已经生成一颗子树,说明可以直接出栈回退
    treeNode* current=p;
    while (!s.empty()||current!=NULL)
    {
        if (current!=NULL) {
            s.push(current);
            current=current->left;
            flag=0;
        }
        else
        {
            if (flag)//从右子树中返回
            {
                current=s.top();s.pop();
                cout<<current->value<<" ";  //访问根结点
                
                // 从根结点返回判断current结点是父结点的左孩子还是右孩子
                if (s.empty()) break;
                treeNode* temp = s.top();
                if (current==temp->left) flag=0;
                else if (current==temp->right) flag=1;
                current=NULL;
                
            }
            else    //从左子树中返回
            {
                current=s.top();
                current=current->right;
                flag=1;
                
            }
        }
    }
    cout<<endl;
}
void LayerPrint(treeNode* p)
{
    queue<treeNode*> q;
    q.push(p);
    treeNode* current;
    while (!q.empty())
    {
        current=q.front();
        q.pop();
        cout<<current->value<<" ";
        if (current->left!=NULL) q.push(current->left);
        if (current->right!=NULL) q.push(current->right);
    }
    cout<<endl;
}
void Insert(node*& p,int value) //在以p为根节点的线索二叉树中插入一个数value
{
    if (p==NULL) {p=new node(value);return;}
    if(p->value==value) return ;
    if (value<p->value) Insert(p->left, value);
    if (value>p->value) Insert(p->right, value);
}
node* createSearchBinaryTree(int a[],int length)
{
    node* root =NULL;
    for (int i=0; i<length; i++) {
        Insert(root, a[i]);
    }
    return root;
}
void print(node *p)
{
    if (p==NULL) return;
    print(p->left);
    cout<<p->value<<" ";
    print(p->right);
}

//一般完全二叉树 生成 中序线索二叉树
treeNode*  first(treeNode* p)//找到以结点p为根节点的子树在中序下的第一个结点
{
    if (p==NULL) return p;
    while (p->ltag==0) {
        p=p->left;
    }
    return p;
}
treeNode* last(treeNode* p)//找到以结点p为根节点的树在中序下的最后一个结点
{
    if (p==NULL) return NULL;
    while (p->rtag==0) {
        p=p->right;
    }
    return p;
}
void createMidThreadBinaryTree(treeNode* p,treeNode* &pre) //线索化以p为根的子树  pre: p的在中序遍历下的前驱
{
    if(p==NULL)return;
    createMidThreadBinaryTree(p->left, pre);
    if (p->left==NULL&&p->ltag==0) {p->left=pre;p->ltag=1;}     //线索化p的前驱
    if(pre!=NULL&&pre->right==NULL){pre->right=p;pre->rtag=1;}  //线索化前驱pre的后继
    pre=p;
    createMidThreadBinaryTree(p->right, pre);
}
void createMidThreadBinaryTree(treeNode* p)
{
    treeNode* t = NULL;
    createMidThreadBinaryTree(p, t);
    if (p==NULL) return;
    treeNode* temp = p;     //别忘了最后一个结点的后驱置空
    while (temp->right!=NULL) {
        temp=temp->right;
    }
    temp->rtag=1;
    
}
//遍历中序线索二叉树

treeNode* Next(treeNode* p)//找到结点P的后驱
{
    if (p==NULL) return NULL;
    if (p->rtag==1) return p->right;
    else return first(p->right);
    
}
void printMidThreadBinaryTree(treeNode* p)
{
    treeNode* one = first(p);
    if (one==NULL) return;
    cout<<one->value<<" ";
    treeNode* next = Next(one);
    while (next!=NULL) {
        cout<<next->value<<" ";
        next = Next(next);
    }
    cout<<endl;
    
}
//A(B(C(D,E)),F(G,H))#
int main(int argc, const char * argv[])
{
    treeNode* head = NULL;
    cout<<"输入广义表,以#结束"<<endl;
    head=createTreeByList('#');
    cout<<"前序遍历"<<endl;
    preOrder(head);
    cout<<endl;
    preOrderND(head);
    cout<<"中序遍历"<<endl;
    midOeder(head);
    cout<<endl;
    midOrderND(head);
    cout<<"后缀遍历"<<endl;
    sufixOrder(head);
    cout<<endl;
    sufixOrderND(head);
    cout<<"层次遍历"<<endl;
    LayerPrint(head);
    cout<<"生成二叉搜索树"<<endl;
    int a[] = {2,3,7,8,9,5,1,4,0,13,7,8,9,23};
    node * root = createSearchBinaryTree(a,14);
    print(root);
    cout<<endl;
    
    cout<<"生成中序线索二叉树"<<endl;
    createMidThreadBinaryTree(head);
    cout<<"遍历中序线索二叉树"<<endl;
    printMidThreadBinaryTree(head);
    return 0;
}

 

内容概要:本文详细介绍了一个基于C++的养老院管理系统的设计与实现,旨在应对人口老龄化带来的管理挑战。系统通过整合住户档案、健康监测、护理计划、任务调度等核心功能,构建了从数据采集、清洗、AI风险预测到服务调度与可视化的完整技术架构。采用C++高性能服务端结合消息队列、规则引擎和机器学习模型,实现了健康状态实时监控、智能任务分配、异常告警推送等功能,并解决了多源数据整合、权限安全、老旧硬件兼容等实际问题。系统支持模块化扩展与流程自定义,提升了养老服务效率、医护协同水平和住户安全保障,同时为运营决策提供数据支持。文中还提供了关键模块的代码示例,如健康指数算法、任务调度器和日志记录组件。; 适合人群:具备C++编程基础,从事软件开或系统设计工作1-3年的研人员,尤其是关注智慧养老、医疗信息系统开的技术人员。; 使用场景及目标:①学习如何在真实项目中应用C++构建高性能、可扩展的管理系统;②掌握多源数据整合、实时健康监控、任务调度与权限控制等复杂业务的技术实现方案;③了解AI模型在养老场景中的落地方式及系统架构设计思路。; 阅读建议:此资源不仅包含系统架构与模型描述,还附有核心代码片段,建议结合整体设计逻辑深入理解各模块之间的协同机制,并可通过重构或扩展代码来加深对系统工程实践的掌握。
内容概要:本文详细介绍了一个基于C++的城市交通流量数据可视化分析系统的设计与实现。系统涵盖数据采集与预处理、存储与管理、分析建模、可视化展示、系统集成扩展以及数据安全与隐私保护六大核心模块。通过多源异构数据融合、高效存储检索、实时处理分析、高交互性可视化界面及模块化架构设计,实现了对城市交通流量的实时监控、历史趋势分析与智能决策支持。文中还提供了关键模块的C++代码示例,如数据采集、清洗、CSV读写、流量统计、异常检测及基于SFML的柱状图绘制,增强了系统的可实现性与实用性。; 适合人群:具备C++编程基础,熟悉数据结构与算法,有一定项目开经验的高校学生、研究人员及从事智能交通系统开的工程师;适合对大数据处理、可视化技术和智慧城市应用感兴趣的技术人员。; 使用场景及目标:①应用于城市交通管理部门,实现交通流量实时监测与拥堵预警;②为市民出行提供路径优化建议;③支持交通政策制定与信号灯配时优化;④作为智慧城市建设中的智能交通子系统,实现与其他城市系统的数据协同。; 阅读建议:建议结合文中代码示例搭建开环境进行实践,重点关注多线程数据采集、异常检测算法与可视化实现细节;可进一步扩展机器学习模型用于流量预测,并集成真实交通数据源进行系统验证。
### 3.1 多通道ADC接口设计 在FPGA中实现40路正弦信号的同步采集,首先需要选择支持多通道并行工作的高速ADC芯片。例如,可使用多个具有LVDS或JESD204B接口的ADC模块,并将它们连接至FPGA的高速IO引脚上。每一路ADC负责独立采集一路正弦波信号,其输出数据通过专用的数据通路送入FPGA内部进行处理[^1]。 为确保各通道之间的同步性,所有ADC应由同一参考时钟驱动,并且采用同步启动机制(如SYNC引脚)来保证采样时刻的一致性。此外,FPGA内部需配置相应的接收逻辑,用于捕获来自ADC的并行或串行数据流,并完成数据对齐与解码操作。 ### 3.2 高速数据缓存与处理 由于40路信号同时传输会产生较大的数据吞吐量,FPGA内部应集成高速数据缓存结构,例如分布式RAM或块RAM(BRAM),用于暂存各通道的原始采样值。为了提升系统效率,可采用双缓冲机制,在一个缓存区写入当前采样数据的同时,另一个缓存区被读取并送往后续处理模块。 在处理阶段,FPGA可以执行以下功能: - **实时滤波**:对采集到的信号应用低通或带通数字滤波器,以去除高频噪声。 - **幅值校准**:根据已知的标准信号调整各通道增益,确保一致性。 - **相位分析**:利用FFT算法计算各路信号的频谱特性,并提取相位信息。 ### 3.3 同步控制与时钟管理 为确保所有通道的采样时间严格一致,系统必须具备精确的时钟分配网络。通常情况下,主控时钟由高性能晶振提供,并通过FPGA内部的锁相环(PLL)或延迟锁定环(DLL)生成多个低抖动的子时钟信号,分别驱动各个ADC模块[^1]。 此外,FPGA还需实现同步脉冲生器,用于触所有ADC同时开始转换。该脉冲可通过外部GPIO引脚出,并与ADC的CONVST信号相连,从而实现全局同步采样。 ### 3.4 数据传输与系统扩展 考虑到40路信号的数据量较大,FPGA应配备高速接口模块,例如千兆以太网、PCIe或USB 3.0,以便将采集结果上传至主机进行进一步分析或存储。对于更复杂的应用场景,还可以采用多个FPGA协同工作的方式,通过高速背板总线或光模块构建分布式采集系统。 ### 示例代码:多通道ADC数据采集控制模块(Verilog) ```verilog module adc_capture_multi ( input clk, // 主时钟 input rst_n, input [7:0] adc_data [0:39], // 40路ADC输入数据 input adc_valid, // 所有通道共用的有效信号 output reg [7:0] fifo_out [0:39], output reg fifo_wr_en ); always @(posedge clk or negedge rst_n) begin if (!rst_n) begin fifo_wr_en <= 1'b0; end else if (adc_valid) begin integer i; for (i = 0; i < 40; i = i + 1) begin fifo_out[i] <= adc_data[i]; end fifo_wr_en <= 1'b1; end else begin fifo_wr_en <= 1'b0; end end // 此处可连接至多通道FIFO或DMA控制器 endmodule ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值