0
点赞
收藏
分享

微信扫一扫

基于人类反馈的强化学习(RLHF)入门指南

江南北 2024-03-09 阅读 10
数据结构

目录

一、线性表中顺序表的实现:

二、线性表的链式存储(链表-带头节点)

三、习题练习:

四、栈(stack)

五、循环队列 

1.数组形式:

2.链表形式: 

3.习题练习 

六、二叉树

1.层次建树 

2.前中后序遍历 (就看中在哪遍历)

3.层序遍历-- 

4.先序遍历求WPL带权路径之和

七、OJ练习题 


一、线性表中顺序表的实现:

#include <stdio.h>

//顺序表的实现
#define MAXSIZE 50  //这里不加引号
typedef int ElemType; //使得顺序表存储其他类型元素时候可以迅速修改类型

typedef struct {
    ElemType data[MAXSIZE];
    int len;
} SequenceTable;

//遍历
void print_list(SequenceTable &list){
    for (int i = 0; i < list.len; ++i) {
        printf("The changed value is:%d\n",list.data[i]);
    }
}

//顺序表中插入元素---这里list要(c++语法)引用
bool addData(SequenceTable &list,int position,ElemType data){
    //判断插入的位置是否合法---首尾判断  不能插入到 len+1以外的地方  不能插入到比1小的位置上
    if(position>list.len+1||position<1){
        printf("The location inserted into the table is illegal");
        return false;
    }
    //判断表中是否还有空间
    if(list.len>=MAXSIZE){
        printf("Insert failure space is full");
        return false;
    }
    //把要插入的空间腾出来  后面的元素往后移动一位
    for (int i = list.len-1; i >=position-1 ; i--) {
        list.data[i+1]=list.data[i];
    }
    //插入元素
    list.data[position-1]=data;
    //顺序表存储的元素长度+1
    list.len++;
    //遍历输出
    print_list(list);
    return true;
}

//删除元素
bool delData(SequenceTable &list,int position){
    //判断删除的位置是否合法
    if(position>list.len||position<=0){
        //删除的位置不合法
        printf("The deleted location is invalid!");
        return false;
    }
    //删除该位置的元素--依次往前覆盖掉要删除的那个位置的元素
    for (int i = position; i < list.len; ++i) {
        list.data[i-1]=list.data[i];
    }
    //删除成功--改变线性表长度
    list.len--;
    //遍历
    print_list(list);
    return true;
}

//修改元素
bool updateData(SequenceTable &list,int position,ElemType value){
    //判断修改的位置是否合法
    if(position>list.len||position<=0){
        //删除的位置不合法
        printf("The deleted location is invalid!");
        return false;
    }
    //修改元素
    list.data[position-1]=value;
    //遍历
    print_list(list);
    return true;
}


int main() {
    SequenceTable list;
    list.data[0]=0;
    list.data[1]=1;
    list.data[2]=2;
    list.data[3]=3;
    list.len=4;
    for (int i = 0; i < list.len; ++i) {
        printf("Change the previous value to:%d\n",list.data[i]);
    }
    //插入
//    addData(list,2,9);
    //删除
//    delData(list,1);
    //修改
    updateData(list,1,8);
    return 0;
}

二、线性表的链式存储(链表-带头节点)

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

//链表实现
typedef int ElementType;//存储的数据域类型

//linkList是指针别名  LNode* 就等价于 linkList
typedef struct LNode{
    ElementType data;//数据域
    struct LNode *next;//指针域
}LNode, *linkList;

//头插法构建链表--注意引用因为要改变
bool buildLinkListByHead(linkList &list){
    //申请(结构体节点)空间创建头节点
    list=(LNode*) malloc(sizeof(LNode));
    //初始化头节点的指针域
    list->next=NULL;
    //循环接收输入的数据 来构建链表
    ElementType x;
    //不要忘记引用
    scanf("%d",&x);
    while (x!=9999){
        //为新节点--申请节点空间
        LNode *new_node=(LNode*) malloc(sizeof (LNode));
        //存储数据
        new_node->data=x;
        //改变新节点的指针域--指向原来头节点的指针域所指向的节点地址
        new_node->next=list->next;
        //改变头节点的指针域--指向该元素
        list->next=new_node;
        //继续接收下一个数--不要忘记引用
        scanf("%d",&x);
    }
    return true;
}

//尾插法构造链表
bool buildLinkListByTail(linkList &list){
    //申请头节点空间
    list=(linkList) malloc(sizeof (LNode));
    //初始化头节点指针域
    list->next=NULL;
    //接收数据x
    ElementType x;
    scanf("%d",&x);
    //记录最后一个节点--初始化
    LNode *tailNode=list;
    while (x!=9999){
        //为新节点申请空间
        LNode *new_node=(LNode*) malloc(sizeof(LNode));
        //存储数据
        new_node->data=x;
        //改变新节点的指针域
        new_node->next=tailNode->next;
        //改变头节点的指针域
        tailNode->next=new_node;
        //插入完成 得到尾部节点
        tailNode=new_node;
        //继续接收数据
        scanf("%d",&x);
    }
    return true;
}

//统计链表的长度
int getLength(linkList list){
    int length=0;
    list=list->next;
    while (list){
        length++;
        list=list->next;
    }
    return length;
}

//按位置查找--本应该返回的是这个位置的节点地址
ElementType getValueByPosition(linkList list,int position){
    int value;
    int length= getLength(list);
    //判断位置是否合法
    if (position>length||position<=0){
        printf("The location entered is invalid!");
        return -1;
    }
    //遍历查找
    for (int i = 0; i < position; ++i) {
        //依次后移到该位置
        list=list->next;
    }
    if (list->data== NULL){
        return -1;
    }
    value=list->data;
    return value;
}

//按位置查找--返回的是这个位置的节点地址
linkList getLNodeByPosition(linkList list,int position){
    int length= getLength(list);
    //判断位置是否合法
    if (position>length||position<=0){
        printf("The location entered is invalid!");
        return NULL;
    }
    //遍历查找
    for (int i = 0; i < position; ++i) {
        //依次后移到该位置
        list=list->next;
    }
    return list;
}

//按值查找
int getPositionByValue(linkList list,int value){
    //得到第一个元素
    list=list->next;
    //记录位置
    int position=0;
    while (list&&list->data==value){
        //记录位置
        position++;
        //依次往后移动
        list=list->next;
    }
    return position;
}

//找到要插入节点的前一个节点
linkList getBeforeNode(linkList list,int position){
    LNode *before_node=list;
    //当前位置
    int current=0;
    for (int i = 0; i < position-1; ++i) {
        before_node=before_node->next;
    }
    return before_node;
}

//往第i个位置插入元素--要改变链表中 某些节点的指针域了  要用 引用
bool listFrontInsert(linkList &list,int position,ElementType e){
    //得到当前链表的长度
    int length= getLength(list);
    //判断插入的位置是否合法
    if (position<=0||position>length+1){
        printf("The insertion position is illegal!\n");
        return false;
    }
    //为要插入的节点申请节点空间
    LNode *new_node=(LNode*) malloc(sizeof(LNode));
    new_node->data=e;
    //得到要插入节点的前一个节点
    LNode *before_node=getBeforeNode(list,position);
    //改变插入节点的指针域
    new_node->next=before_node->next;
    //改变前一个节点的指针域
    before_node->next=new_node;
    return true;
}

//遍历链表--这里不需要引用因为不对链表做改变仅遍历查看
void ergodicList(linkList list){
    //得到头节点所指向的元素
    list=list->next;
    //循环遍历
    while (list!=NULL){
        printf("%3d",list->data);
        //往后移动
        list=list->next;
    }
    //遍历完成--换行
    printf("\n");
}

//链表的删除--要改变指针域 用引用
bool delLNode(linkList &list,int position){
    //得到链表的长度
    int length= getLength(list);
    //判断要删除的位置是否合法
    if (position>length||position<=0){
        printf("The location to be deleted is invalid");
        return false;
    }
    //得到要删除节点的前一个位置的节点
    LNode *before_node= getBeforeNode(list,position);
    //要做非空判断
    if (before_node==NULL){
        return false;
    }
    //得到要删除的节点
    LNode *delNode= getLNodeByPosition(list,position);
    //删除该节点
    before_node->next=delNode->next;
    delNode->next=NULL;
    //释放空间
    free(delNode);
    return true;
}


int main() {
    linkList list;
    //头插法创建链表
//    buildLinkListByHead(list);
    //尾插法创建链表
    buildLinkListByTail(list);
    //遍历查看
    ergodicList(list);
    //按位置查找
//    int value=getValueByPosition(list,5);
//    if (value!=-1){
//        //查找成功
//        printf("%d\n",value);
//    }
//    int position= getPositionByValue(list,9);
//    if (position!=0){
//        //查找成功
//        printf("%d\n",position);
//    }

//    //插入元素
//    listFrontInsert(list,2,90);
    //按位置查找节点
//    LNode *node=getLNodeByPosition(list,2);
//    printf("%d\n",node->data);
    //删除节点
    delLNode(list,1);
    //遍历查看
    ergodicList(list);
    return 0;
}

三、习题练习:

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

typedef struct node{
    int data;//数据域
    struct node *next;//指针域
}node;

//尾插法构造链表
bool buildLinkListByTail(node* &list){
    //申请头节点空间
    list=(node*) malloc(sizeof (node));
    //初始化头节点指针域
    list->next=NULL;
    //接收数据x
    int x;
    scanf("%d",&x);
    //记录最后一个节点--初始化
    node *tailNode=list;
    while (x!=9999){
        //为新节点申请空间
        node *new_node=(node*) malloc(sizeof(node));
        //存储数据
        new_node->data=x;
        //改变新节点的指针域
        new_node->next=tailNode->next;
        //改变头节点的指针域
        tailNode->next=new_node;
        //插入完成 得到尾部节点
        tailNode=new_node;
        //继续接收数据
        scanf("%d",&x);
    }
    return true;
}

//遍历链表--这里不需要引用因为不对链表做改变仅遍历查看
void ergodicList(node* list){
    //得到头节点所指向的元素
    list=list->next;
    //循环遍历
    while (list!=NULL){
        printf("%3d",list->data);
        //往后移动
        list=list->next;
    }
    //遍历完成--换行
    printf("\n");
}

//查询链表的中间位置--并初始化后半部分链表L2--双指针遍历法--注意引用
void findMiddle(node* &L,node* &L2){
    //L非空判断
    if (L==NULL){
        return;
    }
    //为L2创建头节点
    L2=(node*) malloc(sizeof(node));
    //初始化头节点
    L2->next=NULL;
    //双指针遍历法查找中间节点
    node *before,*behind;
    //初始化 这俩个指针--都指向链表L的第一个节点
    before=behind=L->next;
    //循环移动 before每次移动一格  behind每次移动俩格
    while (behind!=NULL){
        //后面节点移动一格---不要一次移动俩格--可能移动一次就为空了
        behind=behind->next;
        //移动一次后--注意这里要非空判断
        if (behind==NULL){
            //说明已经找到了中间位置--这里退出循环
            break;
        }
        //不为空那么可以再移动一次
        behind=behind->next;
        //移动俩次后--要非空判断--因为只要behind为空那么 before是不可以移动的
        if (behind==NULL){
            //说明已经找到了中间位置--这里退出循环
            break;
        }
        //移动before
        before=before->next;
    }
    //移动完成后 before所在的位置即为L2的头节点所在位置
    //before所在的位置的后一个节点即为L2的第一个节点所在位置
    L2->next=before->next;
    //断开L L2连接
    before->next=NULL;
}

//原地翻转后半部分链表L2
void reverse(node* &L2){
    //非空判断
    if (L2==NULL){
        return;
    }
    //准备三个指针
    node *left,*middle,*right;
    //左边指向第一个节点
    left=L2->next;
    //判断第一个节点是否为空
    if (left==NULL){
        return;
    }
    //中间指向第二个节点
    middle=left->next;
    //判断第二个节点是否为空
    if (middle==NULL){
        return;
    }
    //右边指向第三个节点
    right=middle->next;
    //在循环中进行判断
    while (right!=NULL){
        //翻转
        //将中间节点的尾指针指向左边节点
        middle->next=left;
        //三个指针同时移动
        left=middle;//左边节点变中间节点
        middle=right;//中间节点变右边节点
        right=right->next;//右边节点移动一位
    }
    //不要忘记右边节点为空的时候--已经退出了循环--左中节点还未完成翻转
    middle->next=left;
    //因为要翻转--不要忘记L2的最后一个节点指向NULL--即刚开始的第一个节点
    L2->next->next=NULL;
    //翻转完成--重置L2的-第一个节点
    L2->next=middle;
}

//交叉合并俩个链表--三指针法
void merge(node* L,node* L2){
    if (L==NULL||L2==NULL){
        return;
    }
    node *pcur;//始终指向合成的那个链表的尾部
    node *p;//指向L的第二个节点
    node *q;//指向L2的第一个节点
    pcur=L->next;
    p=pcur->next;
    q=L2->next;
    while (p!=NULL){
        //合并第一个q节点
        pcur->next=q;
        pcur=pcur->next;//后移一位pcur
        q=q->next;//后移一位q
        //合并第二个p节点
        pcur->next=p;
        pcur=pcur->next;
        p=p->next;
    }
    //看最后那个剩在哪个上 插入即可
    if (p!=NULL){
        pcur->next=p;
        pcur=pcur->next;
    }
    if (q!=NULL){
        pcur->next=q;
        pcur=pcur->next;
    }
}



int main() {
    //初始链表L
    node* L;
    //尾插法创建链表L
    buildLinkListByTail(L);
    //存储我们翻转后的链表L2
    node* L2=NULL;
    //初始L--遍历查看
    ergodicList(L);
    printf("------------\n");
    //查询链表L的中间位置并初始化后半部分链表为L2
    findMiddle(L,L2);
    //打印L与L2
    ergodicList(L);
    ergodicList(L2);
    printf("------------\n");
    //翻转
    reverse(L2);
    ergodicList(L2);
    printf("-------------\n");
    //合并
    merge(L,L2);
    ergodicList(L);
    return 0;
}

四、栈(stack)

 

#include <stdio.h>

#define MAXSIZE 50
typedef int ElementType;

typedef struct {
    //栈中的元素--数组存储
    ElementType data[MAXSIZE];
    //始终指向栈顶的一个变量--因为是数组因此从0开始
    //空栈为-1
    int top;
}Stack;

//初始化栈
bool InitStack(Stack &stack){
    stack.top=-1;
    return true;
}

//判断栈满
bool isStackFull(Stack stack){
    if (stack.top>=MAXSIZE-1){
        return true;
    }
    return false;
}

//判断栈空
bool isStackEmpty(Stack stack){
    if (stack.top==-1){
        return true;
    }
    return false;
}

//进栈
bool push(Stack &stack,ElementType x){
    //判断栈是否已满
    bool isFull=isStackFull(stack);
    if (isFull){
        return false;
    }
    //进栈
    stack.data[++stack.top]=x;
}


//出栈-返回出栈元素
bool pop(Stack &stack,ElementType &x){
    //判断是否为空
    if (isStackEmpty(stack)){
        return false;
    }
    //出栈
    x=stack.data[stack.top--];
}


int main() {
    Stack stack;
    InitStack(stack);
    push(stack,1);
    push(stack,2);
    ElementType x;
    pop(stack,x);
    printf("%d--%d",x,stack.top);
    return 0;
}

五、循环队列 

1.数组形式:

#include <stdio.h>

#define MAXSIZE 3

typedef int ElementType;
typedef struct {
    //数组存储--只能存储MAXSIZE-1个元素(便于判断队满)
    ElementType data[MAXSIZE];
    //队列尾  队列头
    int rear,front;
}Queue;

//判断队满
bool isQueueFull(Queue queue){
    if ((queue.rear+1)%MAXSIZE==queue.front){
        return true;
    }
    return false;
}

//判断队空
bool isQueueEmpty(Queue queue){
    if (queue.front==queue.rear){
        return true;
    }
    return false;
}

//初始化队列
bool InitQueue(Queue &queue){
    //头和尾都指向零号元素
    queue.front=queue.rear=0;
    return true;
}

//入队
bool push(Queue &queue,ElementType x){
    //判断队满
    if (isQueueFull(queue)){
        return false;
    }
    //入队
    queue.data[queue.rear]=x;
    //注意这里要循环
    queue.rear=(queue.rear+1)%MAXSIZE;
    return true;
}

//出队
bool pop(Queue &queue,ElementType &x){
    if (isQueueEmpty(queue)){
        return false;
    }
    //出队
    x=queue.data[queue.front];
    //注意这里要循环
    queue.front=(queue.front+1)%MAXSIZE;
    return true;
}



int main() {
    Queue queue;
    InitQueue(queue);
    push(queue,1);
    push(queue,2);
    push(queue,3);
    ElementType  x;
    pop(queue,x);
    printf("%d--%d",queue.rear,queue.front);
    return 0;
}

2.链表形式: 

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

//循环队列的链式表示
typedef int ElementType;

//链表
typedef struct LinkNode{
    ElementType data;
    struct LinkNode *next;
}LinkNode;

//链表队列
typedef struct LinkQueue{
    //链表队列头  链表队列尾
    LinkNode *front,*rear;
}LinkQueue;//先进先出

//初始化链表队列
void InitLinkQueue(LinkQueue &linkQueue){
    //申请节点空间
    //都指向头节点
    linkQueue.front=linkQueue.rear=(LinkNode *) malloc(sizeof(LinkNode));
    //初始化头节点
    linkQueue.front->next=NULL;
}

//判断队空
bool isEmpty(LinkQueue queue){
    if (queue.front==queue.rear){
        return true;
    }
    return false;
}

//因为是链表可以自己申请空间 所以不存在队满的情况

//入队--类似尾插法
void push(LinkQueue &queue,ElementType x){
    //为新节点申请空间
    LinkNode *newNode=(LinkNode*) malloc(sizeof(LinkNode));
    newNode->data=x;
    //连接导队列上
    newNode->next=queue.rear->next;
    queue.rear->next=newNode;
    //rear始终指向队列尾
    queue.rear=newNode;

}

//出队--front往后移动
bool pop(LinkQueue &queue,ElementType &x){
    //判断队中是否为空
    if (isEmpty(queue)){
        return false;
    }
    //得到出队的该节点
    LinkNode *node=queue.front->next;
    //出队
    x=node->data;
    //不是最后一个元素-后面还有元素则--断链
    queue.front->next=node->next;
    //判断删除的是否是队列的最后一个节点
    if (node==queue.rear){
        //说明删除完后队列--队列为空了--重置rear与front
        //注意重置是给rear重新指向头节点  因为后面没元素了  要重置就是重置的rear
        queue.rear=queue.front;
    }
    free(node);
    return true;
}

int main() {
    LinkQueue linkQueue;
    InitLinkQueue(linkQueue);
    push(linkQueue,1);
    ElementType x;
    pop(linkQueue,x);
    return 0;
}

3.习题练习 

 

六、二叉树

1.层次建树 

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

//树中元素的存储类型
typedef char BiElementType;

//树的结构
typedef struct BiTNode{
    //存储数据
    BiElementType data;
    //左孩子
    struct BiTNode *lchild;
    //右孩子
    struct BiTNode *rchild;
}BiTNode,*BiTree;

//辅助队列
typedef struct tag{
    //存储的是树中节点的地址
    BiTree p;
    struct tag *pnext;
}tag_t,*ptag_t;
#include "BiTree.h"

int main() {
    //用来指向新申请的树节点
    BiTree tnode;
    //始终指向要插入节点的父亲节点
    BiTree tree=NULL;
    //始终指向树根
    BiTree troot=NULL;
    //接收数据
    BiElementType c;
    //队列头   队列尾  申请新的队列节点空间 pnew  pcur 指向(正在插入左右孩子的)二叉树的根节点
    ptag_t phead=NULL,ptail=NULL,pnew=NULL,pcur=NULL;
    //循环接收键盘输入abcdefjh
    while (scanf("%c",&c)){
        //退出循环
        if (c=='\n'){
            break;
        }
        //创建新的树节点--创建树节点空间--calloc() 俩个参数之积 为申请的空间大小--于malloc相比它会自动初始化--初始化为0  0即为NULL
        tnode=(BiTNode*) calloc(1, sizeof(BiTNode));
        //初始化树节点
        tnode->data=c;
        //申请队列节点空间
        pnew=(tag_t*) calloc(1, sizeof(tag_t));
        //初始化--数据为 树中节点的地址
        pnew->p=tnode;
        //判断树是否为空
        if (tree==NULL){
            //第一次插入树--将当前节点作为树根节点
            troot=tnode;
            //将当前节点作为接下来要插入节点的父亲节点节点
            tree=tnode;
            //入队
            //队列头节点赋值
            phead=pnew;
            //队列中的树根节点--指要进入树的父亲节点
            pcur=pnew;
            //队列尾节点重置
            ptail=pnew;
            //那么这个节点就处理完成了
            continue;
        }
        //如果树不为空判断是否为左孩子
        if (tree->lchild==NULL){
            //左孩子连接树
            tree->lchild=tnode;
            //左孩子入队
            pnew->pnext=ptail->pnext;
            ptail->pnext=pnew;
            //队列尾节点重置
            ptail=pnew;
            //那么这个节点就处理完成了
            continue;
        }
        //如果树不为空判断是否为右孩子
        if (tree->rchild==NULL){
            //右孩子连接到树上
            tree->rchild=tnode;
            //右孩子入队
            pnew->pnext=ptail->pnext;
            ptail->pnext=pnew;
            //注意因为是右孩子因此此时的树根节点以及满了 要改变树根了
            //移动队列中的树根节点
            pcur=pcur->pnext;
            //将辅助队列树根节点赋值给树根节点
            tree=pcur->p;
            //队列尾节点重置
            ptail=pnew;
            //那么这个节点就处理完成了
            continue;
        }
    }

    return 0;
}

2.前中后序遍历 (就看中在哪遍历)

//前序遍历
void preOrder(BiTree tree){
    if (tree==NULL){
        return;
    }
    //中左右
    printf("%c",tree->data);
    //打下面的
    preOrder(tree->lchild);
    preOrder(tree->rchild);
}
//中序
void inOrder(BiTree tree){
    if (tree==NULL){
        return;
    }
    //左中右
    inOrder(tree->lchild);
    printf("%c",tree->data);
    inOrder(tree->rchild);
}

//后序
void postOrder(BiTree p){
    if (p==NULL){
        return;
    }
    //左右中
    postOrder(p->lchild);
    postOrder(p->rchild);
    printf("%c",p->data);
}

3.层序遍历-- 


//层序遍历
void LevelOrder(BiTree troot){
    if (troot==NULL){
        return;
    }
    //辅助队列
    LinkQueue queue;
    InitLinkQueue(queue);
    //树根节点放入队列
    push(queue,troot);
    //存储出队树节点
    BiTNode *deNode;
    while (!isEmpty(queue)){
        pop(queue,deNode);
        putchar(deNode->data);
        if(deNode->lchild){
            //左孩子入队
            push(queue,deNode->lchild);
        }
        if(deNode->rchild){
            //右孩子入队
            push(queue,deNode->rchild);
        }
    }
}

4.先序遍历求WPL带权路径之和

 

 

//先序遍历计算带权路径之和
int wpl_preOrder(BiTree tree,int deep){
    //静态局部变量  它与全局变量作用类似 都只会初始化一次 但它仅在函数内有效
    static int wpl=0;
    if (tree!=NULL){
        if (tree->lchild==NULL&& tree->rchild==NULL){
            wpl+=tree->data*deep;
        }
        wpl_preOrder(tree->lchild,deep+1);
        wpl_preOrder(tree->rchild,deep+1);
    }
    return wpl;
}
//先序遍历计算带权路径之和
int wpl_PreOrder(BiTree tree,int deep){
    if (tree->lchild==NULL&&tree->rchild==NULL){
        return tree->data*deep;
    }
    return wpl_PreOrder(tree->lchild,deep+1)+wpl_PreOrder(tree->rchild,deep+1);
}

七、OJ练习题 

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

/**
 * 读取字符串abcdefghij,然后层次建树建立一颗二叉树,然后前序遍历输出abdhiejcfg,注意不要打印前序遍历几个汉字
 */

/**
 * 读取字符串abcdefghij,然后层次建树建立一颗二叉树,
 * 然后中序遍历输出 hdibjeafcg,后序遍历输出 hidjebfgca,层序遍历输出abcdefghij,注意不要输出汉字
 */

typedef char BiElementType;
typedef struct BiNode{
    BiElementType data;
    BiNode *lchild,*rchild;
}BiNode,*BiTree;

typedef BiTree QElementType;

//辅助链式循环队列
typedef struct LinkNode{
    QElementType data;
    struct LinkNode *next;
}LinkNode,*LinkList;

typedef struct LinkQueue{
    LinkNode *front,*rear;
}LinkQueue;

//判断队列是否为空
bool isEmptyQueue(LinkQueue queue){
    return queue.front==queue.rear;
}
//初始化队列
void InitQueue(LinkQueue &queue){
    queue.rear=queue.front=(LinkNode*) calloc(1,sizeof (LinkNode));
}

//入队
void enQueue(LinkQueue &queue,QElementType data){
    //存储新节点
    LinkNode* qnew=(LinkNode*) calloc(1, sizeof(LinkNode));
    qnew->data=data;
    //入队
    qnew->next=queue.rear->next;
    queue.rear->next=qnew;
    queue.rear=qnew;
}
//出队
BiTree deQueue(LinkQueue &queue){
    if (isEmptyQueue(queue)){
        return NULL;
    }
    //获取当前出队节点
    LinkNode *qNode=queue.front->next;
    //出队
    queue.front->next=qNode->next;
    if (queue.rear==qNode){
        //说明删除的是最后一个节点--重置rear front
        queue.rear=queue.front;
    }
    BiNode *tree=qNode->data;
    //释放空间
    free(qNode);
    return tree;
}

//层次建树
BiTree buildBiTree(BiTree &tree){
    //存储新的树节点
    BiNode *tnew=NULL;
    BiElementType data;
    //创建辅助队列并初始化
    LinkQueue queue;
    InitQueue(queue);
    //队列中--指向要插入的节点的父亲节点
    LinkNode *qroot=NULL;
    //树根节点
    BiTree troot=NULL;
    while (scanf("%c",&data)){
        if (data=='\n'){
            break;
        }
        tnew=(BiNode*) calloc(1,sizeof(BiNode));
        tnew->data=data;
        //判断是否是树根节点
        if (tree==NULL){
            tree=tnew;
            enQueue(queue,tnew);
            //此时队列中的第一个节点作为接下来要插入的父节点
            qroot=queue.front->next;
            troot=tnew;
            continue;
        }
        //判断是否是左孩子节点
        if (tree->lchild==NULL){
            tree->lchild=tnew;
            enQueue(queue,tnew);
            continue;
        }
        //判断是否是右孩子节点
        if (tree->rchild==NULL){
            tree->rchild=tnew;
            enQueue(queue,tnew);
            qroot=qroot->next;
            tree=qroot->data;
            continue;
        }
    }
    return troot;
}

//前序
void preOrder(BiTree tree){
    if (tree==NULL){
        return;
    }
    printf("%c",tree->data);
    preOrder(tree->lchild);
    preOrder(tree->rchild);
}

//中序
void inOrder(BiTree tree){
    if (tree==NULL){
        return;
    }
    inOrder(tree->lchild);
    printf("%c",tree->data);
    inOrder(tree->rchild);
}
//后序
void PostOrder(BiTree tree){
    if (tree==NULL){
        return;
    }
    PostOrder(tree->lchild);
    PostOrder(tree->rchild);
    printf("%c",tree->data);
}
//层序
void SequenceOrder(BiTree tree){
    if (tree==NULL){
        return;
    }
    LinkQueue queue;
    InitQueue(queue);
    enQueue(queue,tree);
    while (!isEmptyQueue(queue)){
        BiNode *tree=deQueue(queue);
        printf("%c",tree->data);
        if (tree->lchild){
            enQueue(queue,tree->lchild);
        }
        if (tree->rchild){
            enQueue(queue,tree->rchild);
        }
    }
}

int main() {
    BiTree tree=NULL;
    BiTree troot=NULL;
    troot=buildBiTree(tree);
    inOrder(troot);
    printf("\n");
    PostOrder(troot);
    printf("\n");
    SequenceOrder(troot);
    printf("\n");
    return 0;
}

 

举报

相关推荐

0 条评论