版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_38038143/article/details/83931543
源码地址 GitHub:https://github.com/GYT0313/C-DataStructure
1. 二叉树
要求:
- 掌握二叉树的二叉链表的创建方法;
- 掌握二叉树的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.哈夫曼编码
要求:
- 掌握哈夫曼树的创建方法;
- 掌握哈夫曼编码的生成方法。
代码:
#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;
}