C语言数据结构-二叉树、哈夫曼、队列小练习

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_38038143/article/details/83931543

源码地址 GitHub:https://github.com/GYT0313/C-DataStructure

1. 二叉树

要求:

  1. 掌握二叉树的二叉链表的创建方法;
  2. 掌握二叉树的3种遍历递归算法;
  3. 掌握二叉树的3种遍历的非递归算法。
    在这里插入图片描述
    代码:
#include <stdio.h>
#include <stdlib.h>

#define M 100

typedef struct node
{
    char data;
    struct node *lchild, *rchild;
}BTNode;



/*
 * 创建二叉树:
 *
 *创建次序为从左到右
 *遇到 # 时返回上一层,标志位变为 2 也就是该节点的右子树
 *右子树为 # 时出栈该节点,并访问父节点的右子树
 *
*/
BTNode *createBiTree( char *str )
{
    BTNode *s[M];   /* 栈 */
    BTNode *b=NULL, *p;  /* b:指向根节点, p:直接新创节点 */
    int top=-1, i=0, flag=1;

    while ( str[i] != '\0')
    {
        if ( str[i] != '#' )
        {
            p = (BTNode *)malloc(sizeof(BTNode));
            p->data = str[i];
            p->lchild = p->rchild = NULL;

            if ( b == NULL )    /* b 指向根节点 */
                b = p;
            else
            {
                switch ( flag )
                {
                case 1:       /* 左子树 */
                    s[top]->lchild = p;
                    break;
                case 2:        /* 右子树 */
                    s[top]->rchild = p;
                    top--;      /* 出栈 */
                    break;
                }
            }
            s[++top] = p;   /* 入栈 */
            flag = 1;
        }
        else
        {
            flag = 2;
            if ( str[i-1] == '#' )      /* 该节点没有左右子树,则出栈 */
                top--;
        }
        i++;
    }

    return b;
}

///////////////// 递归遍历  ////////////////////////
/* 先序递归算法 */
void PreOrder1( BTNode *b )
{
    if ( b == NULL )
        return ;
    else
    {
        printf(" %c", b->data);
        PreOrder1( b->lchild );
        PreOrder1( b->rchild );
    }
}

/* 中序递归算法 */
void InOrder1( BTNode *b )
{
    if ( b == NULL )
        return ;
    else
    {
        InOrder1( b->lchild );
        printf(" %c", b->data);
        InOrder1( b->rchild );
    }
}


/* 后序递归算法 */
void PostOrder1( BTNode *b )
{
    if ( b == NULL )
        return ;
    else
    {
        PostOrder1( b->lchild );
        PostOrder1( b->rchild );
        printf(" %c", b->data);
    }
}

///////////////// 非递归遍历  ////////////////////////
///////////////// 非递归借助于栈来实现


/* 先序非递归算法 */
/*
 *先序遍历从左到右,当p指向空时,该节点出栈,并且 p 指向该节点的右子树
 *若右子树也为空,则出栈该节点的父节点,并且 p 指向父节点的右子树
 *
*/
void PreOrder( BTNode *b )
{
    BTNode *s[M], *p = b;
    int top=-1;

    while ( p != NULL || top != -1 )    /* p不为空,栈不为空 */
    {
        if ( p != NULL )        /* 访问左子树 */
        {
            printf(" %c", p->data);
            s[++top] = p;   /* 入栈 */
            p = p->lchild;
        }
        else        /* 访问右子树 */
        {
            p = s[top--];   /* p 指向栈顶,并且出栈*/
            p = p->rchild;
        }
    }
}

/* 中序非递归算法 */
void InOrder( BTNode *b )
{
    BTNode *s[M], *p = b;
    int top=-1;

    while ( p != NULL || top != -1 )
    {
        if ( p != NULL )
        {
            s[++top] = p;
            p = p->lchild;
        }
        else
        {
            p = s[top--];
            printf(" %c", p->data);
            p = p->rchild;
        }
    }
}


/* 后序非递归算法 */
/*
 *后序与前、中序不同,需要另一个栈来存放对应入栈的标志位
 *当第三次访问该节点时才打印该节点
 *
 *--当打印第一个数后,并不会返回执行if,而是执行else if,也就是父节点的右子树
 *
*/
void PostOrder( BTNode *b )
{
    BTNode *s1[M], *s2[M], *p = b;
    int top=-1;

    while ( p != NULL || top != -1 )
    {
        if ( p != NULL )
        {
            s1[++top] = p;      /* 入栈 */
            p = p->lchild;
            s2[top] = 1;    /* 第 1 次访问该节点 */
        }
        else if ( s2[top] == 1 )
        {
            p = s1[top];
            p = p->rchild;
            s2[top] = 2;    /* 第 2 次访问该节点 */
        }
        else
        {
            p = s1[top--];  /* 出栈 */
            printf(" %c", p->data);
            p = NULL;       /* 跳过直接下次循环的 if 语句, 进行 else if 的判断 */
        }
    }


}


int main()
{
    BTNode *b;
    char str[M];

    gets( str );
    b = createBiTree( str );

    ///////////////////////////////////////
    printf("              Recursion: \n\n");
    printf("PreOrder1:  ");
    PreOrder1( b );     /* 先序递归算法 */
    printf("\n");

    printf("InOrder1:   ");
    InOrder1( b );     /* 中序递归算法 */
    printf("\n");

    printf("PostOrder1: ");
    PostOrder1( b );     /* 后序递归算法 */
    printf("\n\n\n");

    ////////////////////////////////////////
    printf("           No Recursion: \n\n");
    printf("PreOrder:   ");
    PreOrder( b );
    printf("\n");

    printf("InOrder:    ");
    InOrder( b );
    printf("\n");

    printf("PostOrder:  ");
    PostOrder( b );
    printf("\n");

    return 0;
}

2.哈夫曼编码

要求:

  1. 掌握哈夫曼树的创建方法;
  2. 掌握哈夫曼编码的生成方法。
    在这里插入图片描述
    代码:
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>

#define N 8  //字母个数
#define M ( 2*N-1 )  //节点数目


typedef struct      /* HaffmanTree 结构体: weight  parent  lchild  rchild */
{
    int weight;
    int parent, lchild, rchild;
}HTNode;
typedef HTNode HaffmanTree[M];      /* HTNode 类型的数组结构体 */


typedef struct      /* HaffmanTree 结构体: data  weight  code[N] */
{
    char data;
    int weight;
    char code[N];   /* 编码 原本最长:N-1, 最后一位存放'\0'*/
}HTCode;
typedef HTCode HaffmanCode[N];      /* HTCode 类型的数组结构体 */

/* 初始化 haffmancode */
int initHaffmanCode( HaffmanCode hc )  /* hc 是数组 */
{
    int i;

    for (i=0; i<N; i++)
    {
        printf("Please input %d's code and weight: ", i+1);
        fflush(stdin);  /* 清空缓冲区 */
        scanf("%c%d", &hc[i].data, &hc[i].weight);
    }
}


/*初始化 haffmantree*/
/*
 *给叶节点赋 weight,其余赋-1
 */
void initHaffmanTree( HaffmanTree ht, HaffmanCode hc )
{
    int i;

    for (i=0; i<N; i++)
    {
        ht[i].weight = hc[i].weight;    /*初始化 weight*/
    }

    for (i=0; i<M; i++)
    {
        ht[i].parent = ht[i].lchild = ht[i].rchild = -1;   /*赋值 -1*/
    }
}


/*创建 哈夫曼树*/
void createHaffmanTree( HaffmanTree ht )
{
    int i, j;
    int min1, min2, index1, index2;     /*最小值、 次小值、 最小值下标、 次小值下标*/

    for (i=N; i<M; i++)     /*查找 min1 和 min2*/
    {
        min1 = min2 = INT_MAX;  /* int类型的最大值  (引入头文件limts.h)*/
        index1 = index2 = -1;
        for (j=0; j<i; j++)     /*注:每次查找的范围在扩大(+1)*/
        {
            if (ht[j].parent == -1)     /*没有双亲才比较*/
            {
                if (ht[j].weight < min1)    /* ht[j].weight < min1 < min2 */
                {
                    min2 = min1;    /*原来的最小值变为了次小值*/
                    index2 = index1;
                    min1 = ht[j].weight;    /*新的最小值为 ht[j].weight */
                    index1 = j;
                }
                else if(ht[j].weight < min2)
                {
                    min2 = ht[j].weight;    /* min1 < ht[j].weight < min2 */
                    index2 = j;
                }
            }
        }
        ht[i].weight = min1 + min2;     /* 计算新权值,最小值 和 次小值相加得到二者的双亲节点的权值 */
        ht[i].lchild = index1;    /* 最小值在左 */
        ht[i].rchild = index2;   /* 次小在右 */              /* 修改父节点 */

        ht[index1].parent = ht[index2].parent = i;  /* 最小值 和 次小值的 parent */     /* 修改两个子树节点 */
    }
}

/*创建 哈夫曼代码*/
void createHaffmanCode( HaffmanTree ht, HaffmanCode hc )
{
    char code[N];   /*暂时存放哈夫曼代码*/
    int i, j, start;

    for (i=0; i<N; i++)     /*倒叙查找*/
    {
        start = N - 1;
        code[start] = '\0';
        j = i;
        while(ht[j].parent != -1)   /*到达根节点跳出*/
        {
            code[--start] = ht[ht[j].parent].lchild == j?'0':'1'; /* 双亲的lchild == 该节点的下标,即值为0,否则为1 */
            j = ht[j].parent;   /*双亲的下标*/
        }
        strcpy(hc[i].code, &code[start]);   /*code 是数组, 有值的地方的地址(因为是倒叙)赋给 hc[i].code(相当于赋首地址)*/
    }

}


/*打印 code*/
void printCode( HaffmanCode hc )
{
    int i;

    for (i=0; i<N; i++)
    {
        printf("%c的编码是: %s\n", hc[i].data, hc[i].code);
    }
}



int main()
{
    HaffmanCode hc;
    HaffmanTree ht;

    initHaffmanCode(hc);       /*初始化*/
    initHaffmanTree(ht, hc);

    createHaffmanTree(ht);     /*创建*/
    createHaffmanCode(ht, hc);

    printCode(hc);

    return 0;
}

3. 队列

要求:
1. 输入说明:输入为一行正整数,其中第1个数字N(N<=1000)为顾客总数,后面跟着N位顾客的编号。编号为奇数的顾客需要到A窗口办理业务,为偶数顾客则去B窗口。数字以空格分隔。
2. 输出说明:按业务处理完成的顺序输出顾客的编号。数字间以空格分隔,但最后一个编号不能有多余的空格。
Question I:从键盘接收顾客编号
Question II:随机生成顾客编号
Question III:按照 A-B 窗口处理速度

在这里插入图片描述
代码:

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

typedef struct node     /* 指向数据的结构体 */
{
    int Data;
    struct node *Next;
} Qnode;

typedef struct link     /* 指向节点的结构体 */
{
    Qnode *Front, *Rear;
    struct link *Next;
} LinkQueue;


/* 初始化 */
LinkQueue *initQueue()
{
    LinkQueue *q;
    Qnode *p;

    q = (LinkQueue *)malloc(sizeof(LinkQueue));
    q->Front = q->Rear = (Qnode *)malloc(sizeof(Qnode));
    q->Front->Next = NULL;

    return q;
}


/* 是否为空,为空返回1 */
int isEmpty( LinkQueue *q )
{
    if ( q->Front == q->Rear )
        return 1;
    else
        return 0;
}


/* 入队 A 窗口*/
void EnqueueA( LinkQueue *q, int data )
{
    Qnode *p;

    p = (Qnode *)malloc(sizeof(Qnode));

    p->Data = data;
    p->Next = NULL;

    q->Rear->Next = p;
    q->Rear = p;
}

/* 入队 B 窗口 */
void EnqueueB( LinkQueue *q, int data )
{
    Qnode *p;

    p = (Qnode *)malloc(sizeof(Qnode));

    p->Data = data;
    p->Next = NULL;

    q->Rear->Next = p;
    q->Rear = p;
}

/* 出队 */
void OutQueue( LinkQueue *q, int *queue )
{
    if ( isEmpty(q) )
        return '#';

    Qnode *p, *m;

    p = q->Front->Next;
    q->Front->Next = p->Next;   /* 队头指向下一个节点 */
    *queue = p->Data;

    m = q->Front;
    while( m->Next )    /* m 指向队尾*/
        m = m->Next;
    q->Rear = m;
}

/* Question I II 打印语句 */
void print( int N, LinkQueue *qA, LinkQueue *qB, int *queue )
{
    int i, flag=0;      /* flag 判断 A 出队次数 */
    /* 入队 */
    for ( i=0; i<N; i++ )
    {
        if ( queue[i]%2 == 1 )  /* 奇数到 A 窗口 */
        {
            EnqueueA( qA, queue[i] );
        }
        else                    /* 偶数到 B 窗口 */
            EnqueueB( qB, queue[i] );
    }
    /* 出队 */
    for ( i=0; i<N; i++ )
    {
        if ( flag < 2 && !isEmpty( qA ))    /* A 出队 */
        {
            OutQueue( qA, &queue[i] );
            flag++;
        }
        else if ( !isEmpty( qB ) )          /* B 出队 */
        {
            OutQueue( qB, &queue[i] );
            flag = 0;
        }
        else
        {
            if ( !isEmpty( qA ) )
                OutQueue( qA, &queue[i] );
            else if ( !isEmpty( qB ) )
                OutQueue( qB, &queue[i] );
            flag = 0;
        }
    }

    printf("The order of queue: ");
    for ( i=0; i<N; i++ )
        printf(" %d", queue[i]);
    printf("\n");
}

/* Question III 打印语句 */
void print2( int N, int NA, int NB, LinkQueue *qA, LinkQueue *qB, int *queue )
{
    int i, flag=0, flag2=0;     /* flag 判断 A 出队次数, flag2 判断 B 出队次数 */
    /* 入队 */
    for ( i=0; i<N; i++ )
    {
        if ( queue[i]%2 == 1 )  /* 奇数到 A 窗口 */
        {
            EnqueueA( qA, queue[i] );
        }
        else                    /* 偶数到 B 窗口 */
            EnqueueB( qB, queue[i] );
    }
    /* 出队 */
    for ( i=0; i<N; i++ )
    {
        if ( flag < NA && !isEmpty( qA ))       /* A 出队 */
        {
            OutQueue( qA, &queue[i] );
            flag++;
            flag2 = 0;
        }
        else if ( !isEmpty( qB ) )          /* B 出队 */
        {
            OutQueue( qB, &queue[i] );
            flag2++;
            if ( flag2 >= NB )      /* 判断 B 出队次数是否满足 */
                flag = 0;
        }
        else
        {
            if ( !isEmpty( qA ) )
                OutQueue( qA, &queue[i] );
            else if ( !isEmpty( qB ) )
                OutQueue( qB, &queue[i] );
            flag = 0;
            flag2 = 0;
        }
    }

    printf("The order of queue: ");
    for ( i=0; i<N; i++ )
        printf(" %d", queue[i]);
    printf("\n");
}


int main()
{
    LinkQueue *qA, *qB;
    int N;
    int queue[1000], i;
    int NA, NB;

    qA = initQueue();
    qB = initQueue();

    printf("Question I:\n");        /* 从键盘接收 */
    printf("N: ");
    scanf("%d", &N);
    for ( i=0; i<N; i++ )
        scanf("%d", &queue[i]);
    print( N, qA, qB, queue );


    ////////////////////////////////////////////////////
    printf("\n");
    printf("Question II:\n");       /* 按照 rand() 计算 */
    printf("N: ");
    scanf("%d", &N);
    for ( i=0; i<N; i++ )
        queue[i] = rand()%1000+1;

    printf("The rand number: ");
    for(i=0; i<N; i++)
        printf("%d ", queue[i]);
        printf("\n");
    print( N, qA, qB, queue );


    ////////////////////////////////////////////////////
    printf("\n");
    printf("Question III:\n");      /* 按照 NA : NB 计算 */
    printf("N: ");
    scanf("%d", &N);
    printf("NA:NB: ");
    scanf("%d%d", &NA, &NB);
    for ( i=0; i<N; i++ )
        queue[i] = rand()%1000+1;

    printf("The rand number: ");
    for(i=0; i<N; i++)
        printf("%d ", queue[i]);
        printf("\n");
    print2( N, NA, NB, qA, qB, queue );

    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_38038143/article/details/83931543