14.C++考研数据结构树代码部分

目录

一、存储结构

1.顺序存储

(1)定义

(2)初始化

(3)打印

2.链式存储(二叉树链式存储)

(1)定义

(2)初始化

(3)创建(一个一个加)

二、层次建树

1.function.h头文件,存储数据结构定义

2.创建

三、遍历

1.前序(根左右)(深度优先遍历)

2.中序(左根右)

3.后序(左右根)

4、层序遍历

2.事前准备

(1)function.h

(2)queue.cpp

2.思路 利用辅助队列,先把根结点入队,当队列不为空时,出队,并判断左右结点是否为null,不是null则入队,循环往复

3.代码实现

四、线索二叉树

1.定义

2.初始化

3.插入结点

4.土办法找中序遍历的前驱(二叉树)

5.利用线索二叉树(中序找前驱)

6.前序找前驱

五、树的存储结构

1.双亲表示法

2.孩子兄弟表示法

六、并查集

1.创建

2.初始化

3.增加元素

4.查

5.并

6.优化

(1)优化Union

(2)优化Find


一、存储结构

1.顺序存储

(1)定义

typedef int ElemType;
#define MaxSize 10
typedef struct SqTree{
    ElemType data[MaxSize];
}SqTree;

(2)初始化

void InitTree(SqTree &T){
    for (int i = 1; i < MaxSize; ++i) {
        T.data[i] = i;
    }
}

(3)打印

void print(SqTree T){
    for (int i = 1; i < MaxSize; ++i) {
        printf("%d",T.data[i]);
    }
    printf("\n");
}

2.链式存储(二叉树链式存储)

(1)定义

typedef struct BiTNode{
    ElemType data;
    struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

(2)初始化

void InitBiTree(BiTree &BT){
    BT = (BiTNode*)malloc(sizeof(BiTNode));
    BT->lchild = NULL;
    BT->rchild = NULL;
}

(3)创建(一个一个加)

void AddTreeNode(BiTNode *&Node,ElemType e){
    if(Node == NULL){ //非头结点
        Node = (BiTNode*)malloc(sizeof (BiTNode));
        Node->data  = e;
        Node->lchild = NULL;
        Node ->rchild = NULL;
    }
    Node->data = e;//头结点
}

二、层次建树

1.function.h头文件,存储数据结构定义

//function.h

typedef char BiElemType;

//单个结点
typedef struct BiTNode{
    BiElemType c;
    struct BiTNode *lchild;
    struct BiTNode *rchild;
}BiTNode,*BiTree;

//tag结构体是辅助队列(链队)使用的
typedef struct tag{
    BiTree p;
    struct tag *pnext;
}tag_t,*ptag_t;

2.创建

int main()
{
    BiTree pnew;//用来申请新的树节点
    BiTree tree=NULL;//根节点,必须声明为空树
    char c;

    ptag_t phead=NULL,ptail=NULL,listpnew=NULL,pcur;
//phead队列头,ptail队列尾,listpnew指向链表队列中的新结点,pcur指向新来的元素放在树的哪个位置
    while(scanf("%c",&c)){
        if (c=='\n') //不存换行符号
        {
            break;
        }
        pnew = (BiTree)calloc(1,sizeof (BiTNode));
        //calloc() stdlib.h
        //申请的空间是1*sizeof(BiTree),两个参数相乘
        //and在申请时左右孩子空间也是0了(同时初始化)
        //so不用malloc
        pnew->c=c;//存数据

        //给辅助队列结点申请空间
        listpnew= (ptag_t)calloc(1,sizeof(tag_t));
        listpnew-> p = pnew;
        if(NULL == tree){//树的第一个结点
            tree=pnew;//tree指向根节点
            phead =listpnew;//一个结点的时候既是头部也是尾部
            ptail = listpnew;
            pcur = listpnew;//pcur指向父亲结点
        }else{//后面的
            ptail->pnext = listpnew;
            ptail = listpnew;
            if(NULL == pcur ->p->lchild) {
                pcur ->p->lchild= pnew;
            }
            else if(NULL == pcur ->p->rchild){
                pcur ->p->rchild= pnew;
                pcur = pcur	->pnext;
            }
        }
    }
}

三、遍历

1.前序(根左右)(深度优先遍历)

void PreOrder(BiTree BT){
    if(BT != NULL){
        visit(BT);
        PreOrder(BT->lchild);
        PreOrder(BT->rchild);
    }
}

2.中序(左根右)

//中序遍历
void InOrder(BiTree BT){
    if(BT!=NULL) {
        PreOrder(BT->lchild);
        visit(BT);
        PreOrder(BT->rchild);
    }
}

3.后序(左右根)

void PostOrder(BiTree BT){
    if(BT != NULL){
        PostOrder(BT->lchild);
        PostOrder(BT->rchild);
        visit(BT);
    }
}

4、层序遍历

void LevelOrder(BiTree BT) {
    LinkQueue Q;
    InitQueue(Q);
    EnQueue(Q,BT);
    BiTree p;//用于输出
    while(!isEmpty(Q)){
        DeQueue(Q,p);
        visit(p);
        if(p->lchild != NULL){
            EnQueue(Q,p->lchild);
        }
        if(p->rchild != NULL){
            EnQueue(Q,p->lchild);
        }
    }
}

2.事前准备

创建二叉树,创建queue.cpp和function.h

(1)function.h



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

typedef char ElemType;
//单个结点
typedef struct BiTNode{
    ElemType c;
    struct BiTNode *lchild;
    struct BiTNode *rchild;
}BiTNode,*BiTree;

//tag结构体是辅助队列(链队)使用的
typedef struct tag{
    BiTree p;
    struct tag *pnext;
}tag_t,*ptag_t;


typedef BiTree BiElemType;
//队列的链式存储 LinkQueue
//有头尾指针的单链表
//链表
typedef struct LinkNode{
    BiElemType data;
    struct LinkNode *next;
}LinkNode;

//链表队列
typedef struct {
    LinkNode *front,*rear;//队头队尾(链表头、尾)
}LinkQueue;

(2)queue.cpp

#include "function.h"

bool IsEmpty(LinkQueue Q){
    return Q.front == Q.rear;
}


void InitQueue(LinkQueue &Q){
    Q.front= Q.rear = (LinkNode*)malloc(sizeof (LinkNode));
    Q.front->next =NULL;
}

void EnQueue(LinkQueue &Q,BiElemType x){
    LinkNode *pnew = (LinkNode*)malloc(sizeof (LinkNode));
    pnew ->data = x;
    pnew ->next = NULL;//否则无法停止
    Q.rear ->next = pnew;//尾指针指向pnew
    Q.rear = pnew;//新的尾部
}

bool DeQueue(LinkQueue &Q,BiElemType &x){
    if(Q.rear == Q.front){//空的
        return false;
    }
    LinkNode* q = Q.front ->next;//第一个结点
    x = q->data;//获取出队的元素值
    Q.front->next = q ->next;
    if(Q.rear == q){//只剩1个结点
        Q.rear = Q.front;
    }
    free(q);//断链
    return true;
}

2.思路
 利用辅助队列,先把根结点入队,当队列不为空时,出队,并判断左右结点是否为null,不是null则入队,循环往复

3.代码实现

void LevelOrder(BiTree T){
	LinkQueue Q;//辅助队列
	InitQueue(Q);
	BiTree p;//存储出队结点
	EnQueue(Q,T);//树根入队
	while(!IsEmpty(Q)){
		DeQueue(Q,p);
		putchar(p->c);
		if(p->lchild){
			EnQueue(Q,p->lchild);
		}
		if(p->rchild){
			EnQueue(Q,p->rchild);
		}
	}
}

四、线索二叉树

1.定义

typedef char ElemType;

typedef struct ThreadNode {
    ElemType data;
    struct ThreadNode *lchild, *rchild;
    int ltag, rtag;
} ThreadNode, *ThreadTree;

2.初始化

void InitThreadTree(ThreadTree &TT) {
    TT = (ThreadNode *) malloc(sizeof(ThreadNode));
    TT->lchild = NULL;
    TT->rchild = NULL;
    TT->ltag = 0;
    TT->rtag = 0;
}

3.插入结点

void AddTreeNode(ThreadNode *&Node, ElemType e) {
    if (Node == NULL) { //非头结点
        Node = (ThreadNode *) malloc(sizeof(ThreadNode));
        Node->data = e;
        Node->lchild = NULL;
        Node->rchild = NULL;
        Node ->ltag = 0;
        Node ->rtag = 0;
    }
    Node->data = e;//头结点
}

4.土办法找中序遍历的前驱(二叉树)

attn:全局变量是在main()之外,p指针要指向结点,不能直接赋值

全局变量
BiTNode *p;
BiTNode *pre=NULL;
BiTNode *final=NULL;
//函数
void visit(BiTNode *q){
    if(q!=NULL){
        //指针引用直接 变量名
        if(q == p) final = pre;
        else pre = q;
    }
}

void InOrderFindPre(BiTree TT){
    if(TT!=NULL){
        InOrderFindPre(TT->lchild);
        visit(TT);
        InOrderFindPre(TT->rchild);
    }
}

5.利用线索二叉树(中序找前驱)

//全局变量
ThreadNode *p;
ThreadNode *pre = NULL;
//函数
void InThreadVisit(ThreadNode *q) {
    if (q->lchild == NULL) {//左孩子为null,指向前驱
        q->lchild = pre;//左孩子指向pre
        q->ltag = 1;
    }
    if (pre != NULL && pre->rchild == NULL ) {//指后继
        pre->rchild = q;
        pre->rtag = 1;
    }
    pre = q;//访问下一个结点
}

//利用线索二叉树
//结果剩下最后一个结点没有线索化
void InThread(ThreadTree &TT) {
    if (TT != NULL) {//左孩子为null
        InThread(TT->lchild);
        InThreadVisit(TT);
        InThread(TT->rchild);
    }
}

void CreateInThread(ThreadTree &T) {
    pre = NULL;
    if (T != NULL) {
        InThread(T);
        pre->rchild = NULL;//完善最后一个右节点
        pre->rtag = 1;
    }
}

6.前序找前驱

//全局变量
ThreadNode *p;
ThreadNode *pre = NULL;
//函数
void PreThreadVisit(ThreadTree &q) {
    if (q->lchild == NULL) {
        q->lchild = pre;
        q->ltag = 1;
    }
    if (pre != NULL && pre->rchild == NULL) {
        pre->rchild = q;
        pre->ltag = 1;
    }
    pre = q;
}

void PreThread(ThreadTree &q) {
    if (q != NULL) {
        PreThreadVisit(q);
        if (q->ltag == 0) { //if此结点的左孩子的前驱正好是此结点,则会发生死循环,so用tag判断
            //so该结点左孩子的前驱不是该结点时即该结点左孩子为空
            PreThread(q->lchild);
        }
        PreThread(q->rchild);
    }
}

void CreatePreThread(ThreadTree &TT) {
    pre = NULL;
    if (TT != NULL) {
        PreThread(TT);
        if(TT->rchild == NULL) {
            TT->rtag = 1;
        }
    }
}

五、树的存储结构

1.双亲表示法

typedef char ElemType;
#define MAX_TREE_SIZE 100
typedef struct {//结点
    ElemType data;
    int parent;
}PTNode;

typedef struct{//整体
    PTNode nodes[MAX_TREE_SIZE];
    int n;
}PTree;

2.孩子兄弟表示法

typedef struct CSNode{
    ElemType data;
    struct CSNode *lchild,*nextsibling;
}CSNode,*CSTree;

六、并查集

1.创建

#define SIZE 100
int UFSets[SIZE];

2.初始化

void Initial(int S[]){
    for (int i = 0; i < SIZE; ++i) {
        S[i] = -1;
    }
}

3.增加元素

void add(int S[]){
    S[1] = 0;
    for (int i = 2; i < 4; ++i) {
        S[i] = -1;
    }
    for (int i = 4; i < 6; ++i) {
        S[i] = 1;
    }
    S[6] = 2;
    for (int i = 7; i < 10; ++i) {
        S[i] = 3;
    }
    for (int i = 10; i < 12; ++i) {
        S[i] = 4;
    }
    S[12] = 7;
}

4.查

int Find(int S[],int x){
    while(S[x] >= 0){//x的父节点不是-1,x不是根节点
        x = S[x];
    }
    return x;//x的根的下标
}

5.并

void Union(int S[],int Root1,int Root2){
    if(Root1 == Root2) return;
    S[Root2] = Root1;//2到1下
}

6.优化

(1)优化Union

//增加元素
void addPer(int S[]) {
    S[0] = -6;
    S[2] = -2;
    S[3] = -5;
    S[1] = 0;
    for (int i = 4; i < 6; ++i) {
        S[i] = 1;
    }
    S[6] = 2;
    for (int i = 7; i < 10; ++i) {
        S[i] = 3;
    }
    for (int i = 10; i < 12; ++i) {
        S[i] = 4;
    }
    S[12] = 7;
}
void UnionPer(int S[], int Root1, int Root2) {
    if (Root1 == Root2) return;
    if (S[Root2] > S[Root1]) {//-2>-6 2浅 让2 归1
        S[Root1] += S[Root2];
        S[Root2] = Root1;
    } else {
        S[Root2] += S[Root1];
        S[Root1] = Root2;
    }
}

(2)优化Find

int FindPer(int S[],int x){
    //先找到根结点下标,再修改
    int root = x;
    while(S[root] >= 0){
        root = S[root];
    }
    while(x!= root){
        int t = S[x];//记录真实父节点
        S[x] = root;
        x =  t;
    }
    return root;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

kid_star

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

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

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

打赏作者

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

抵扣说明:

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

余额充值