数据结构实现

目录

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

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

三、习题练习:

四、栈(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;//顺序表存储的元素长度+1list.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;
}

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

注意:

        头插法构建链表:不要忘记引用--画图看指针域的改变--注意改变顺序

        尾插法构建链表:要记录尾部节点--画图看指针域变化

按位置查找的时候返回节点地址:--(可以返回头节点地址--便于删除操作)

或者自己写一个单独获取前一个节点的方法  

便于后续对链表的插入操作时查找要插入元素的前一个节点位置

       节点的删除-----画图看指针域变化--注意要判断拿到的前一个节点是否为NULL

        拿前一个节点的时候这个获取的方法是可以获取到头节点的

        注意删除某个节点的时候不要忘记free() 释放该节点地址空间

       

typedef int ElementType;//存储的数据域类型

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

#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;//接收数据xElementType 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;
}

三、习题练习:

 1.一次循环--得中间节点--俩个指针   一个走2 一个走1

 2.原地逆置--                  -- 三个指针  

 3.轮流合并--                  -- 三个指针

不清楚该不该引用  就再增删改的时候加引用即可

注意逆置侯L2的第一个节点要重置 且 第一个节点的尾指针要指向NULL

#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;//接收数据xint 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;}//移动beforebefore=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;//后移一位pcurq=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() {//初始链表Lnode* L;//尾插法创建链表LbuildLinkListByTail(L);//存储我们翻转后的链表L2node* L2=NULL;//初始L--遍历查看ergodicList(L);printf("------------\n");//查询链表L的中间位置并初始化后半部分链表为L2findMiddle(L,L2);//打印L与L2ergodicList(L);ergodicList(L2);printf("------------\n");//翻转reverse(L2);ergodicList(L2);printf("-------------\n");//合并merge(L,L2);ergodicList(L);return 0;
}

四、栈(stack)

栈:数组实现

初始化栈:栈顶=-1 即为空栈

出栈:并不会改变数组 --只是让栈顶-1

入栈:会改变数组元素  

 

#include <stdio.h>#define MAXSIZE 50
typedef int ElementType;typedef struct {//栈中的元素--数组存储ElementType data[MAXSIZE];//始终指向栈顶的一个变量--因为是数组因此从0开始//空栈为-1int 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.数组形式:

1.注意是循环队列

queue.rear=(queue.rear+1)%MAXSIZE;
queue.front=(queue.front+1)%MAXSIZE;

判断队空:--画图

queue.front==queue.rear

判断队满:--画图

(queue.rear+1)%MAXSIZE==queue.front

#include <stdio.h>#define MAXSIZE 3typedef 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.链表形式: 

尾插法:入队

出队: 头节点连接下一个

具体可以看动画

Data Structure Visualization (usfca.edu)

注意:

        初始化链表队列时候 头节点的尾指针

        出队的时候要判断删除完后是否为队空 如果队空 --重置front与rear--free()-注意顺序

        重置front与rear: queue.rear=queue.front----注意重置的是rear

        出队:判断栈空--出队-得到第一个节点-改变front--判断队空--free

#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重新指向头节点  因为后面没元素了  要重置就是重置的rearqueue.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;//循环接收键盘输入abcdefjhwhile (scanf("%c",&c)){//退出循环if (c=='\n'){break;}//创建新的树节点--创建树节点空间--calloc() 俩个参数之积 为申请的空间大小--于malloc相比它会自动初始化--初始化为0  0即为NULLtnode=(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);}}
}

 注意队列最后一个节点出队的front与rear的重置

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

 

 

 第一种,使用静态局部遍历累加的形式:

                1.遍历左孩子 deep+1

                2.遍历右孩子 deep+1

 第二种,使用递归直接返回:

                1.这个递归表示该子树的带权路径之和=左子树+右子树的带权路径之和

                2.返回条件为如果这个节点满足叶子节点就返回它的带权路径

//先序遍历计算带权路径之和
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练习题 

注意增删改加引用

注意当第一个节点入队的时候

将这第一个节点作为接下来的父亲节点 qroot=queue.front->next   不要忘记next

#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 frontqueue.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;
}

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/730864.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

226. 翻转二叉树

代码实现&#xff1a; 方法1&#xff1a;先序遍历 /*** Definition for a binary tree node.* struct TreeNode {* int val;* struct TreeNode *left;* struct TreeNode *right;* };*/// 交换左右子树 void swap(struct TreeNode *root) {struct TreeNode *l root…

Linux grep

文章目录 1. 基本用法2.字符转义3.二进制文件查找4.打印目标字段的附近行4. 多条件过滤5. 目录中过滤——用于在文件夹中筛选/排除指定后缀文件6.反向过滤——用于筛选7.只输出匹配内容——用于统计8. 筛选出包含字段的文件9.正则匹配10.管道和grep11.grep和wc/uniq/sort的合用…

B端系统优化,可不是换个颜色和图标,看看与大厂系统的差距。

Hi&#xff0c;我是贝格前端工场&#xff0c;优化升级各类管理系统的界面和体验&#xff0c;是我们核心业务之一&#xff0c;欢迎老铁们评论点赞互动&#xff0c;有需求可以私信我们 一、不要被流于表面的需求描述迷惑。 很多人找我们优化系统界面&#xff0c;对需求总是轻描淡…

小白跟做江科大51单片机之AD/DA

1.看原理图找接口 2.看时序图编写读取数据代码 XPT2046.c代码 #include <REGX52.H> //引脚定义 sbit XPY2046_DINP3^4; sbit XPY2046_CSP3^5; sbit XPY2046_DCLKP3^6; sbit XPY2046_DOUTP3^7; unsigned int XPT2046_ReadAD(unsigned char Command) { unsigned char …

sqllab 11-22

11.有回显&#xff0c;单引号 首先判断是字符型还是数字型 通过order by 来获取字段数 方便后续union联合 注意这里mime表明了内容要进行url编码&#xff0c;测试3报错&#xff0c;2正常&#xff0c;所以有2列。 还需要判断显示位&#xff0c;因为只有显示位的数据才能被爆出…

论文笔记:Efficient Bootstrapping for Confidential Transactions

EcoBoost: Efficient Bootstrapping for Confidential Transactions 设计了一种被称为EcoBoost的新方法&#xff0c;以提高支持机密交易的区块链的引导效率。具体来说&#xff0c;利用随机抽样来验证高概率保密交易的正确性。因此&#xff0c;与事务数量相比**&#xff0c;验证…

【FPGA】DDR3学习笔记(一)丨SDRAM原理详解

本篇文章包含的内容 一、DDR3简介1.1 DDR3 SDRAM概述1.2 SDRAM的基础结构 二、 SDRAM操作时序2.1 SDRAM操作指令2.2 模式寄存器&#xff08;LOAD MODE REGISTER&#xff09;2.3 SDRAM操作时序示例2.3.1 SDRAM初始化时序2.3.2 突发读时序2.3.3 随机读时序2.3.4 突发写时序2.3.5 …

Python学习笔记-Flask实现简单的抽奖程序(增加图片显示)

1.创建static文件夹,存放图片文件 2.hero列表数据更改为要抽奖的图片名 3.html中可以编写python语句,遍历hero列表内容渲染到表格中 4.在点击随机抽取后,可以获得名称,然后使用img标签,将获取的名称拼接到路径中 3.初始页面,访问127.0.0.1:5000/index 4.点击随机抽取后 5.py…

【深入理解设计模式】享元设计模式

享元设计模式 概述 享元设计模式&#xff08;Flyweight Design Pattern&#xff09;是一种用于性能优化的设计模式&#xff0c;它通过共享尽可能多的相似对象来减少对象的创建&#xff0c;从而降低内存使用和提高性能。享元模式的核心思想是将对象的共享部分提取出来&#xff…

实用干货:分享4个冷门但非常实用的HTML属性

大家好&#xff0c;我是大澈&#xff01; 本文约1100字&#xff0c;整篇阅读大约需要2分钟。 关注微信公众号&#xff1a;“程序员大澈”&#xff0c;免费加入问答群&#xff0c;一起交流技术难题与未来&#xff01; 现在关注公众号&#xff0c;免费送你 ”前后端入行大礼包…

TensorRT是什么,有什么作用,如何使用

TensorRT 是由 NVIDIA 提供的一个高性能深度学习推理&#xff08;inference&#xff09;引擎。它专为生产环境中的部署而设计&#xff0c;用于提高在 NVIDIA GPU 上运行的深度学习模型的推理速度和效率。以下是关于 TensorRT 的详细介绍&#xff1a; TensorRT 是 NVIDIA 推出的…

freeRTOS20240308

1.总结任务的调度算法&#xff0c;把实现代码再写一下 2.总结任务的状态以及是怎么样进行转换的

Java集合面试题(day 02)

&#x1f4d1;前言 本文主要是【JAVA】——Java集合面试题的文章&#xff0c;如果有什么需要改进的地方还请大佬指出⛺️ &#x1f3ac;作者简介&#xff1a;大家好&#xff0c;我是听风与他&#x1f947; ☁️博客首页&#xff1a;CSDN主页听风与他 &#x1f304;每日一句&am…

容器: string

引言: 为什么要有string类型, 就使用字符数组表示字符串不行吗? 原因: 使用字符数组描述文本信息, 无法确定开多大空间, 开多了浪费,开少了不够用使用string封装: 扩容机制:减少了空间的浪费各种接口:方便修改等操作 string的使用 容量相关 size:获取字符个数,不包含\0 (C语言…

从huggingface下载模型像本地加载但是UnicodeDecodeError

我自己是在Linux下出现了这个问题 原文&#xff1a;https://github.com/huggingface/transformers/issues/13674 The path for the AutoModel should be to a directory pointing to a pytorch_model.bin and to a config.json. Since you’re pointing to the .bin file dire…

无限debugger的几种处理方式

不少网站会在代码中加入‘debugger’&#xff0c;使你F12时一直卡在debugger&#xff0c;这种措施会让新手朋友束手无策。 js中创建debugger的方式有很多&#xff0c;基础的形式有&#xff1a; ①直接创建debugger debugger; ②通过eval创建debugger&#xff08;在虚拟机中…

安全防御-第七次

在FW5和FW6之间建立一条IPSEC通道保证10.0.2.0/24网段可以正常访问到192.168.1.0/24 NAT&#xff1a; 安全策略&#xff1a; NAT: 安全策略&#xff1a; 修改服务器映射&#xff1a; 配置IPSEC&#xff1a;

物联网的商业模式洞察

大约在十年前&#xff08;2014年11月&#xff09;&#xff0c;全球知名管理思想家、哈佛商学院教授迈克尔波特与PTC前首席执行官吉姆赫普尔曼&#xff0c;在《哈佛商业评论》上联合撰写了一篇备受赞誉的文章&#xff0c;题为《智能互联产品如何改变竞争》。在这篇文章中&#x…

零基础,学6个月嵌入式,能找到工作吗?

今天看到一个老铁问&#xff0c;他报了个班&#xff0c;学6个月&#xff0c;学完能找到工作吗&#xff1f; 我看了下他的学习内容&#xff0c;包含C语言、数据结构、系统编程、网络编程、STM32、RTOS、物联网通讯协议、Linux内核驱动&#xff0c;这是大纲&#xff0c;细节的课程…

AIOPS:Zabbix结合讯飞星火做自动化告警+邮件通知并基于人工智能提供解决方案

目前Zabbix官方已经提供Zabbix+ChatGPT的解决方案 ChatGPT一周年,你充分利用了吗?Zabbix+ChatGPT,轻松化解告警! 但是由于需要魔法等其他因素,比较不稳定,遂决定使用国内模型,这里我挑选的是讯飞星火,基于我之前的文档,在此基础上通过Zabbix的告警脚本实现调用AI模型…