zl程序教程

您现在的位置是:首页 >  后端

当前栏目

《数据结构》树和二叉树代码整理(C语言实现)

2023-09-11 14:20:51 时间

目录

前言:

先序创建二叉树

二叉树遍历(前|中|后 序)--递归(核心代码)

二叉树遍历(前|中|后|层 序)--非递归(核心代码)

后序 双栈法

点这里有个C++ 版,方法很多,只会C的话应该能看懂思路

点这里有思路清晰的C语言版本

点这里有个后续遍历的不错思路——节点里增加了一个变量记录次数(或者用哈希表也可以)

求二叉树高度

按树状打印二叉树

输出二叉树叶子节点并统计叶子节点的数目

哈夫曼树(编码)

二叉搜索树--递归--插入,删除,和查找

二叉搜索树--非递归--插入、删除和查找

 由前序中序重建二叉树

 由中序后序重建二叉树

【Morris_Traversal】二叉树遍历(前|中|后 序)--非递归--不用栈--(完整代码)

前言:

排版很难看,没办法,主要是因为。。。。。。算了不解释了我就是懒。


先序创建二叉树

(这里用了C++  <引用>的特性,使用二重指针代替或者将函数返回值设成指针再做点小修改也能实现)

void CreateTree(TreeRoot &Root)
{//创建(先序)
    char c;
    c=getchar();
    if(c!='#')
    {
        Root=(TreeRoot)malloc(sizeof(TNode));
        Root->data=c;
        CreateTree(Root->pleft);
        CreateTree(Root->pright);
    }
    else
    {
        Root=NULL;
    }
}

二叉树遍历(前|中|后 序)--递归(核心代码)

void InorderTraversal( BinTree BT )
{
    if( BT ) {
        InorderTraversal( BT->Left );
        /* 此处假设对BT结点的访问就是打印数据 */
        printf("%d ", BT->Data); /* 假设数据为整型 */
        InorderTraversal( BT->Right );
    }
}

void PreorderTraversal( BinTree BT )
{
    if( BT ) {
        printf("%d ", BT->Data );
        PreorderTraversal( BT->Left );
        PreorderTraversal( BT->Right );
    }
}

void PostorderTraversal( BinTree BT )
{
    if( BT ) {
        PostorderTraversal( BT->Left );
        PostorderTraversal( BT->Right );
        printf("%d ", BT->Data);
    }
}

————————————————
版权声明:本文为CSDN博主「BrianOne」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Brianone/article/details/89440024

二叉树遍历(前|中|后|层 序)--非递归(核心代码)

void PreOrderFDG(TreeRoot Root)
{//先序遍历非递归
    SqStack S;
    InitStack(S);
    while(Root!=NULL || Empty(S)==0)
    {
        if(Root!=NULL)
        {
            printf("%c ",Root->data);
            Push(S,Root);
            Root=Root->pleft;
        }
        else
        {
            Pop(S,Root);
            Root=Root->pright;
        }
    }
}
void InOrderFDG(TreeRoot Root)
{//中序遍历非递归
    SqStack S;
    InitStack(S);
    while(Root!=NULL || Empty(S)==0)
    {
        if(Root!=NULL)
        {
            Push(S,Root);
            Root=Root->pleft;
        }
        else
        {
            Pop(S,Root);
            printf("%c ",Root->data);
            Root=Root->pright;
        }
    }
}
//后序遍历非递归算法
typedef struct SNode{
    BiTree p;
    int tag;
}SNode;
//后序遍历使用的进栈函数
void postpush(SNode *a,SNode sdata){
    a[++top]=sdata;
}
//后序遍历函数
void PostOrderTraverse(BiTree Tree){
    SNode a[20];//定义一个顺序栈
    BiTNode * p;//临时指针
    int tag;
    SNode sdata;
    p=Tree;
    while (p||top!=-1) {
        while (p) {
            //为该结点入栈做准备
            sdata.p=p;
            sdata.tag=0;//由于遍历是左孩子,设置标志位为0
            postpush(a, sdata);//压栈
            p=p->lchild;//以该结点为根结点,遍历左孩子
        }
        sdata=a[top];//取栈顶元素
        pop();//栈顶元素弹栈
        p=sdata.p;
        tag=sdata.tag;
        //如果tag==0,说明该结点还没有遍历它的右孩子
        if (tag==0) {
            sdata.p=p;
            sdata.tag=1;
            postpush(a, sdata);//更改该结点的标志位,重新压栈
            p=p->rchild;//以该结点的右孩子为根结点,重复循环
        }
        //如果取出来的栈顶元素的tag==1,说明此结点左右子树都遍历完了,可以调用操作函数了
        else{
            displayElem(p);
            p=NULL;
        }
    }
}

后序 双栈法

void NotRecursionPostOrder(BTree T){
  PLinkStack S,CS;
  S=Init_Stack();
  CS=Init_Stack();
  while(T || !empty_Stack(S)){
    if(T){
      Push_Stack(S,T);
      Push_Stack(CS,T);
      T=T->right;
    }else{
      T=Pop_Stack(S)->data;
      T=T->left;
    }
  }
  while(CS->top!=NULL){
    printf("%c",CS->top->data->element);
    CS->top=CS->top->next;
  }
  DestroyStack(CS);
}
void LevelorderTraversal ( BinTree BT )//层序遍历
{
    Queue Q;
    BinTree T;

    if ( !BT ) return; /* 若是空树则直接返回 */

    Q = CreatQueue(); /* 创建空队列Q */
    AddQ( Q, BT );
    while ( !IsEmpty(Q) ) {
        T = DeleteQ( Q );
        printf("%d ", T->Data); /* 访问取出队列的结点 */
        if ( T->Left )   AddQ( Q, T->Left );
        if ( T->Right )  AddQ( Q, T->Right );
    }

————————————————
版权声明:本文为CSDN博主「BrianOne」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/Brianone/article/details/89440024

点这里有个C++ 版,方法很多,只会C的话应该能看懂思路

点这里有思路清晰的C语言版本

点这里有个后续遍历的不错思路——节点里增加了一个变量记录次数(或者用哈希表也可以)

后序遍历方法挺多,多搜一搜,特别是C++ 代码最好也能看看,有很多优秀的实现都是c++版的。

求二叉树高度

int PostTreeDepth(TreeRoot Root)
{//求二叉树的高度
    int hl,hr,max;
    if(Root!=NULL)
    {
        hl=PostTreeDepth(Root->pleft);
        hr=PostTreeDepth(Root->pright);
        max=hl>hr?hl:hr;
        return max+1;
    }
    else
        return 0;
}

按树状打印二叉树

void PrintTree(TreeRoot Root,int nLayer)
{//按树状打印二叉树
    int i;
    if(Root==NULL)
        return ;
    PrintTree(Root->pright,nLayer+1);
    for(i=0;i<=nLayer;i++)
    {
        printf("  ");
    }
    printf("%c\n",Root->data);
    PrintTree(Root->pleft,nLayer+1);
}

输出二叉树叶子节点并统计叶子节点的数目

void PreOrderLeaf(TreeRoot Root)
{//输出二叉树的叶子结点,并统计叶子结点的数目
    if(Root!=NULL)
    {
        if(Root->pleft==NULL && Root->pright==NULL)
        {
            printf("%c ",Root->data);
            leafcount++;
        }
        PreOrderLeaf(Root->pleft);
        PreOrderLeaf(Root->pright);
    }
}

哈夫曼树(编码)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
typedef struct hfNode {
    int weight;
    struct hfNode* lch, * rch, * pnt;
}hfNode;

void selMin(hfNode* nodes, int n, int* a, int* b) { //求两个最小值的下标
    int temp[3] = { 0x3f3f3f3f,0x3f3f3f3f,0x3f3f3f3f };
    int i;
    for (i = 0; i < n; ++i) {
        //printf("%d,%d;", temp[1], temp[2]);
        if (nodes[i].pnt == 0) {
            int t = nodes[i].weight;
            if (temp[1] == 0x3f3f3f3f) {
                temp[1] = t;
                *a = i;
            }
            else if (temp[2] == 0x3f3f3f3f) {
                temp[2] = t;
                *b = i;
            }
            else if (temp[1] > t) {
                temp[1] = t;
                *a = i;
            }
            else if (temp[2] > t) {
                temp[2] = t;
                *b = i;
            }
        }
        //printf("%d,%d;\n", temp[1], temp[2]);
    }
}

void CreateTree(hfNode* nodes, char** hfCode, int* w, int n) {  //构造 Huffman Tree   规定向左走则生成0  右 1
    int m = 2 * n - 1;
    int j;
    int len;
    char* helper = (char*)malloc(2 * n * sizeof(char));

    for (int i = n; i < m; ++i) {
        int a, b;
        selMin(nodes, m, &a, &b);
        nodes[i].pnt = 0;
        nodes[i].lch = &nodes[a];
        nodes[i].rch = &nodes[b];
        nodes[a].pnt = &nodes[i];
        nodes[b].pnt = &nodes[i];
        nodes[i].weight = nodes[a].weight + nodes[b].weight;
    }
    //树建立完毕 下面开始生成哈夫曼码
    for (int i = 0; i < n; ++i) {
        hfNode* cur = nodes + i;
        j = 0;
        while (cur->pnt != 0) {
            hfNode* p = cur->pnt;
            if (p->lch == cur) {
                helper[j++] = '0';
            }
            else {
                helper[j++] = '1';
            }
            cur = cur->pnt;
        }
        hfCode[i] = (char*)malloc(sizeof(char) * (j + 1));
        len = 0;
        while (j > 0) {
            hfCode[i][len++] = helper[--j];
        }
        hfCode[i][len] = '\0';
    }
    free(helper);
}
void show(char** hfCode, int n) {
    //int n;
    int i;
    printf("\n按照输入顺序   哈夫曼编码依次为:\n");
    //printf("%d,%d\n", sizeof(hfCode) , sizeof(char*));
    //n = sizeof(hfCode) / sizeof(char*);
    for (i = 0; i < n; ++i) {
        printf("%s\n", hfCode[i]);
    }
    printf("\n================================\n");
}
void main() {
    hfNode* nodes;
    char** hfCode;
    int n;
    int* w;
    int i;
    printf("请输入字符数量:\n");
    scanf("%d", &n);
    w = (int*)malloc(n * sizeof(char*));
    hfCode = (char**)malloc(n * sizeof(char*));
    nodes = (hfNode*)malloc((2 * n - 1) * sizeof(hfNode));
    printf("请依次输入字符权重:\n");
    for (i = 0; i < n; ++i) {
        scanf("%d", w + i);
        (nodes + i)->weight = w[i];
        (nodes + i)->lch = (nodes + i)->rch = (nodes + i)->pnt = 0;
    }
    CreateTree(nodes, hfCode, w, n);
    show(hfCode, n);
    printf("%p,%p", (nodes + 1)->pnt, (nodes + 3)->pnt);
    free(w);
    free(nodes);
    free(hfCode);

}
/*
A  B  C  D
3  1  2  1
应该的编码之一应该为:

0
101
11
100
*/

二叉搜索树--递归--插入,删除,和查找

//二叉查找树   递归实现  插入,删除和查找
#include<stdio.h>
#include<stdlib.h>

typedef struct Node {
    int val;
    struct Node* left;
    struct Node* right;
}Node;
typedef int bool;

Node * Find(Node* root,int a);   //如果找到了返回指针 如果找不到则返回空指针
Node *Insert(Node* root, int a);  //将a插入到root中并且返回根节点指针
Node *Delete(Node* root,int a);   //将a从root中删除并且返回根节点指针
Node* FindMin(Node* root);//找到最小节点并且返回该节点的指针
Node* FindMax(Node* root);//找到最大节点并且返回该节点的指针
void PreorderTraversal(Node* root); //先序遍历
int main(){
    Node* root = (Node*)malloc(sizeof(Node));//根节点
    Node * BST, *MinP, *MaxP, *Tmp;   //分别是树根节点   最小节点 最大节点 和一个临时用的节点指针变量
    int X;
    int N, i;
    BST = NULL;
    scanf("%d", &N);//插入节点
    for (i = 0; i < N; i++) {
        scanf("%d", &X);
        BST = Insert(BST, X);
    }
    printf("Preorder:"); PreorderTraversal(BST); printf("\n");//先序遍历
    MinP = FindMin(BST);
    MaxP = FindMax(BST);
    scanf("%d", &N);//查找节点
    for (i = 0; i < N; i++) {
        scanf("%d", &X);
        Tmp = Find(BST, X);
        if (Tmp == NULL) printf("%d is not found\n", X);
        else {
            printf("%d is found\n", Tmp->val);
            if (Tmp == MinP) printf("%d is the smallest key\n", Tmp->val);
            if (Tmp == MaxP) printf("%d is the largest key\n", Tmp->val);
        }
    }
    scanf("%d", &N);//删除节点
    for (i = 0; i < N; i++) {
        scanf("%d", &X);
        BST = Delete(BST, X);
    }
    printf("Preorder:"); PreorderTraversal(BST); printf("\n");//先序遍历
    return 0;
}

Node *Find(Node* root,int a) { //查找
    if (!root) return NULL;
    if (a == root->val) {
        return root;
    }
    else if (a > root->val) {
        return Find(root->right, a);
    }
    else {//a< root->val
        return Find(root->left, a);
    }
    return NULL;//实际上这一行是没有必要的
}
Node *Insert(Node* root, int a) {
    if (!root) {
        Node* newNode = (Node*)malloc(sizeof(Node));
        newNode->val = a;
        newNode->left = newNode->right = NULL;
        return newNode;
    }
    else if (a > root->val) {
        root->right = Insert(root->right, a);
    }
    else if (a < root->val) {
        root->left = Insert(root->left, a);
    }
    else {
        //这时候root的节点值等于a则不处理
    }
    return root;
}
Node* Delete(Node* root, int a) {
    if (!root) return root;
    if (a < root->val)       root->left = Delete(root->left, a);
    else if(a > root->val)   root->right = Delete(root->right, a);
    else{  //找到这个节点  那么进行删除操作  此刻要考虑四种情况:左右空 左右非空 左空右非空 左非空右空
        if (!root->left) { Node* temp = root; root = root->right; free(temp); }
        else if (!root->right) { Node* temp = root; root = root->left;free(temp); }
        else {
            Node* temp = root->right;
            while (temp->left) {
                temp = temp->left;
            }
            temp->left = root->left;
            root = root->right;
        }
    }
    return root;//这一句实际上没有必要
}
Node* FindMin(Node* root) {
    if (!root) {
        return NULL;
    }
    if (!root->left) {
        return root;
    }
    return FindMin(root->left);
}
Node* FindMax(Node* root) {
    if (!root) {
        return NULL;
    }
    if (!root->right) {
        return root;
    }
    return FindMax(root->right);
}
void PreorderTraversal(Node* root) {
    if (!root) return;
    printf("%d  ", root->val);
    PreorderTraversal(root->left);
    PreorderTraversal(root->right);
}

二叉搜索树--非递归--插入、删除和查找

#define _CRT_SECURE_NO_WARNINGS
//二叉查找树   非递归实现  插入,删除和查找
#include<stdio.h>
#include<stdlib.h>

typedef struct Node {
    int val;
    struct Node* left;
    struct Node* right;
}Node;
typedef int bool;

Node* Find(Node* root, int a);   //如果找到了返回指针 如果找不到则返回空指针
Node* Insert(Node* root, int a);  //将a插入到root中并且返回根节点指针
Node* Delete(Node* root, int a);   //将a从root中删除并且返回根节点指针
Node* FindMin(Node* root);//找到最小节点并且返回该节点的指针
Node* FindMax(Node* root);//找到最大节点并且返回该节点的指针
void PreorderTraversal(Node* root); //先序遍历
int main() {
    Node* root = (Node*)malloc(sizeof(Node));//根节点
    Node* BST, * MinP, * MaxP, * Tmp;   //分别是树根节点   最小节点 最大节点 和一个临时用的节点指针变量
    int X;
    int N, i;
    BST = NULL;
    scanf("%d", &N);//插入节点
    for (i = 0; i < N; i++) {
        scanf("%d", &X);
        BST = Insert(BST, X);
    }
    printf("Preorder:"); PreorderTraversal(BST); printf("\n");//先序遍历
    MinP = FindMin(BST);
    MaxP = FindMax(BST);
    scanf("%d", &N);//查找节点
    for (i = 0; i < N; i++) {
        scanf("%d", &X);
        Tmp = Find(BST, X);
        if (Tmp == NULL) printf("%d is not found\n", X);
        else {
            printf("%d is found\n", Tmp->val);
            if (Tmp == MinP) printf("%d is the smallest key\n", Tmp->val);
            if (Tmp == MaxP) printf("%d is the largest key\n", Tmp->val);
        }
    }
    scanf("%d", &N);//删除节点
    for (i = 0; i < N; i++) {
        scanf("%d", &X);
        BST = Delete(BST, X);
    }
    printf("Preorder:"); PreorderTraversal(BST); printf("\n");//先序遍历
    return 0;
}
Node* Find(Node* root, int a) { //查找
    if (!root) return NULL;
    while (root) {
        if (a == root->val) {
            break;
        }
        else if (a > root->val) {
            root = root->right;
        }
        else {//a< root->val
            root = root->left;
        }
    }
    return root;
}
Node* Insert(Node* root, int a) {
    if (!root) {
        root = (Node*)malloc(sizeof(Node));
        root->val = a;
        root->left = root->right = NULL;
    }
    else {
        Node* cur = root;
        Node* pre = NULL;
        while (cur) {
            if (a > cur->val) {
                pre = cur;
                cur = cur->right;
            }
            else if (a < cur->val) {
                pre = cur;
                cur = cur->left;
            }
            else {
                break;//找到了值为a的节点
            }
        }
        if (!cur) {  //如果没有找到 则插入
            if (a < pre->val) {
                pre->left = (Node*)malloc(sizeof(Node));
                pre->left->left = pre->left->right = NULL;
                pre->left->val = a;
            }
            else {
                pre->right = (Node*)malloc(sizeof(Node));
                pre->right->left = pre->right->right = NULL;
                pre->right->val = a;
            }
        }
    }
    return root;
}
Node* Delete(Node* root, int a) {//为什么代码这么长?因为没用到递归也没用到引用 就需要一个pre
    if (!root) return root;//根节点为空
    Node* pre = NULL;
    Node* cur = root;
    while (cur) {
        if (a < cur->val) {
            pre = cur;
            cur = cur->left;
        }
        else if (a > cur->val) {
            pre = cur;
            cur = cur->right;
        }
        else {
            if ((!cur->left) && (!cur->right)) {
                if (!pre) {//cur为根节点
                    free(cur);
                    return pre;
                }
                if (a < pre->val) {
                    pre->left = NULL;
                }
                else {
                    pre->right = NULL;
                }
                return root;
            }
            else if (!cur->right) {
                if (!pre) {
                    cur = cur->left;
                    free(root);
                    return cur;
                }
                if (a < pre->val) {
                    pre->left = cur->left;
                    free(cur);
                }
                else {
                    pre->right = cur->left;
                    free(cur);
                }
                return root;
            }
            else if (!cur->left) {
                if (!pre) {
                    cur = cur->right;
                    free(root);
                    return cur;
                }
                if (a < pre->val) {
                    pre->left = cur->right;
                    free(cur);
                }
                else {
                    pre->right = cur->right;
                    free(cur);
                }
                return root;
            }
            else {
                Node* temp = cur->left;
                while (temp->right) {
                    temp = temp->right;
                }
                temp->right = cur->right;
                if (!pre) { Node* t = cur->left; free(cur); return t; };
                if (a < pre->val) {
                    pre->left = cur->left;
                }
                else {
                    pre->right = cur->left;
                }
                free(cur);
                return root;
            }
        }
    }
    return root;
}
Node* FindMin(Node* root) {
    if (!root) {
        return NULL;
    }
    while (root->left) {
        root = root->left;
    }
    return root;
}
Node* FindMax(Node* root) {
    if (!root) {
        return NULL;
    }
    while (root->right) {
        root = root->right;
    }
    return root;
}
void PreorderTraversal(Node* root) {
    if (!root) return;
    printf("%d  ", root->val);
    PreorderTraversal(root->left);
    PreorderTraversal(root->right);
}

 由前序中序重建二叉树

 由中序后序重建二叉树

【Morris_Traversal】二叉树遍历(前|中|后 序)--非递归--不用栈--(完整代码)

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#define DataType int
#define nullptr 0
#define MAXN 2048
typedef struct node {
    DataType data;
    struct node* pleft;
    struct node* pright;
}TNode, * TreeRoot;
TNode* CreateTree() {//构建二叉树  (先序)
    int a;
    scanf("%d", &a);
    if (a != -1){
        TNode* ne = (TNode*)malloc(sizeof(TNode));
        ne->data = a;
        ne->pleft = CreateTree();
        ne->pright = CreateTree();
        return ne;
    }
    return nullptr;
}
void traversal_pre(TNode * root) { //先序遍历二叉树morris_traversal  (已过测试集)
    while (root) {
        if (root->pleft) {
            TNode* rightmost = root->pleft;
            while (rightmost->pright&&rightmost->pright!=root) {
                rightmost = rightmost->pright;
            }
            if (rightmost->pright) {
                rightmost->pright = nullptr;
                root = root->pright;
            }
            else {
                printf("%d ", root->data); //输出数据
                rightmost->pright = root;
                root = root->pleft;
            }
        }
        else {
            printf("%d ", root->data); //输出数据
            root = root->pright;
        }
    }
}
void traversal_mid(TNode* root) { //中序遍历二叉树morris_traversal  (已过测试集)
    while (root) {
        if (root->pleft) {
            TNode* rightmost = root->pleft;
            while (rightmost->pright && rightmost->pright != root) {
                rightmost = rightmost->pright;
            }
            if (rightmost->pright) {
                rightmost->pright = nullptr;
                printf("%d ", root->data); //输出数据
                root = root->pright;
            }
            else {
                rightmost->pright = root;
                root = root->pleft;
            }
        }
        else {
            printf("%d ", root->data); //输出数据
            root = root->pright;
        }
    }
}
void traversal_pos(TNode* root) { //后序遍历二叉树morris_traversal    (已过测试集)
    int temp[MAXN];
    int n = 0;
    while (root) {
        if (root->pright) {
            TNode* lm = root->pright;
            while (lm->pleft&&lm->pleft != root) {
                lm = lm->pleft;
            }
            if (lm->pleft) {
                lm->pleft = nullptr;
                root = root->pleft;
            }
            else {
                lm->pleft = root;
                //printf("%d", root->data);
                temp[n++] = root->data;
                root = root->pright;
            }
        }
        else {
            temp[n++] = root->data;
            root = root->pleft;
        }
    }
    while (n) {
        printf("%d ", temp[--n]);
    }
}
int main() {
    TNode * tree = CreateTree();  //创建二叉树

    //traversal_pre(tree);
    //traversal_mid(tree);
    traversal_pos(tree);
    //system("pause");
    return 0;
}
/*
空树: -1
 ==============
     1

:1 -1 -1
先序遍历结果; 1
中序遍历结果: 1
后序遍历结果:1
=======================
      1
    2

:1 2 -1 -1 -1
先序遍历结果: 1  2
中序遍历结果: 2  1
后序遍历结果:2  1
=======================
      1
        2

:1 -1 2 -1 -1
先序遍历结果: 1  2
中序遍历结果: 1  2
后序遍历结果:2  1
=======================
       1
    2      3
      4   5  6

:1 2 -1 4 -1 -1 3 5 -1 -1 6 -1 -1
先序遍历结果:1  2  4  3  5  6
中序遍历结果:2  4  1  5  3  6
后序遍历结果: 4  2  5  6  3  1
*/