数据结构 二叉树 C语言

该程序的功能是实现二叉树结点的类型定义和对二叉树的基本操作。该程序包括二叉树结构类型以及每一种操作的具体的函数定义和主函数。

/* 定义DataType为char类型 */
typedef char DataType;
 
/* 二叉树的结点类型 */
typedef struct BitNode
{DataType data;
     struct BitNode *lchild,*rchild;
}BitNode,*BitTree;
 
/* 按先序次序建立一个二叉树*/
void BinTreeCreat(BitTree *BT) 
 
/* 按任一种遍历次序(包括按先序、中序、后序)输出二叉树中的所有结点 */
void BinTraverse(BitTree *BT) 
 
/* 求二叉树中所有结点数 */
int  BinTreeCount(BitTree BT)
 
/* 求二叉树的叶子结点个数 */
int BinTreeDepth(BitTree BT)

一,实现二叉树中序遍历非递归算法。

/* 定义DataType为char类型 */
typedef char DataType;
 
/* 二叉树的结点类型 */
typedef struct BitNode
{DataType data;
     struct BitNode *lchild,*rchild;
}BitNode,*BitTree;

  1. 实现二叉树的基本操作
    2) 按先序次序建立一个二叉树*/
void BinTreeCreat(BitTree *BT)

3)实现二叉树中序遍历非递归算法。

二,实现哈夫曼树的构建以及哈夫码编码的实现
数据结构

typedef  struct
{  int weight;
   int parent,lchild,rchild;
}HTNode,*HuffmanTree;//动态分配数组存储Huffman树

在这里插入图片描述

源代码:

// 二叉树.cpp: 定义控制台应用程序的入口点。
//
//author: 小柳学渣
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
//author: 小柳学渣
typedef char TElemType;/*定义二叉树数据元素类型*/

/*定义二叉树结点*/
typedef struct BiTNode
{
	TElemType data;
	struct BiTNode *lchild, *rchild;
}BiTNode, *BiTree;

typedef int Status;
typedef BiTree SElemType;/*定义栈数据类型*/
typedef BiTree QElemType;/*定义队列数据类型*/
//author: 小柳学渣
#define OK 1
#define ERROR 0
#define OVERFLOW 0

#define STACK_INIT_SIZE 100
#define STACKINCREMENT 10

int count;//计数器,全局变量,递归计算符合条件的结点个数
//author: 小柳学渣
/*栈的基本操作*/
typedef struct
{
	SElemType *base;
	SElemType *top;
	int stacksize;
}SqStack;

/*创建栈*/
Status InitStack(SqStack &S)
{
	S.base = (SElemType*)malloc(STACK_INIT_SIZE * sizeof(SElemType));
	if (!S.base)
		exit(OVERFLOW);
	S.top = S.base;
	S.stacksize = STACK_INIT_SIZE;
	return OK;
}

/*栈顶元素*/
Status GetTop(SqStack S, SElemType &e)
{
	if (S.top == S.base)
		return ERROR;
	e = *(S.top - 1);
	return OK;
}

/*插入到栈*/
Status Push(SqStack &S, SElemType e)
{
	if (S.top - S.base >= S.stacksize)
	{
		S.base = (SElemType*)realloc(S.base, (S.stacksize + STACKINCREMENT) * sizeof(SElemType));
		if (!S.base)
			exit(OVERFLOW);
		S.top = S.base + S.stacksize;
		S.stacksize += STACKINCREMENT;
	}
	*S.top++ = e;
	return OK;
}

/*删除栈顶元素*/
Status Pop(SqStack &S, SElemType &e)
{
	if (S.top == S.base)
		return ERROR;
	e = *--S.top;
	return OK;
}

/*判断栈是否为空*/
Status StackEmpty(SqStack &S)
{
	if (S.top != S.base)
		return ERROR;
	return OK;
}

/*重置为空栈*/
Status ClearStack(SqStack &S)
{
	S.top = S.base;
	return OK;
}

/*销毁栈*/
Status DestroyStack(SqStack &S)
{
	free(S.base);
	S.base = NULL;
	S.top = NULL;
	S.stacksize = 0;
	return OK;
}

/*链队列的基本操作*/
typedef struct QNode
{
	QElemType data;
	struct QNode *next;
}QNode, *QueuePtr;

typedef struct
{
	QueuePtr front;
	QueuePtr rear;
}LinkQueue;

/*构造*/
Status InitQueue(LinkQueue &Q)
{
	Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));
	if (!Q.front)
	{
		printf("存储分配失败");
		system("pause");
		exit(OVERFLOW);
	}
	Q.front->next = NULL;
	return OK;
}

/*销毁*/
Status DestroyQueue(LinkQueue &Q)
{
	while (Q.front)
	{
		Q.rear = Q.front->next;
		free(Q.front);
		Q.front = Q.rear;
	}
	return OK;
}

/*插入*/
Status EnQueue(LinkQueue &Q, QElemType e)
{
	QueuePtr p;
	p = (QueuePtr)malloc(sizeof(QNode));
	if (!p)
	{
		printf("存储分配失败");
		system("pause");
		exit(OVERFLOW);
	}
	p->data = e;
	p->next = NULL;
	Q.rear->next = p;
	Q.rear = p;
	return OK;
}

/*删除*/
Status DeQueue(LinkQueue &Q, QElemType &e)
{
	QueuePtr p;
	if (Q.front == Q.rear)
	{
		printf("队列为空");
		return ERROR;
	}
	p = Q.front->next;
	e = p->data;
	Q.front->next = p->next;
	if (Q.rear == p)
		Q.rear = Q.front;
	free(p);
	return OK;
}

/*判断是否为空*/
Status QueueEmpty(LinkQueue &Q)
{
	if (Q.front == Q.rear)
		return 1;
	else
		return 0;
}

/*循环队列基本操作(与链队列的方法重载,参数类型不同)*/
#define MAXQSIZE 100

typedef struct
{
	QElemType *base;
	int front;
	int rear;
}SqQueue;

/*构造*/
Status InitQueue(SqQueue &Q)
{
	Q.base = (QElemType*)malloc(MAXQSIZE * sizeof(QElemType));
	if (!Q.base)
	{
		printf("存储分配失败");
		system("pause");
		exit(OVERFLOW);
	}
	Q.front = Q.rear = 0;
	return OK;
}

/*长度*/
Status QueueLength(SqQueue &Q)
{
	return (Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
}

/*插入*/
Status EnQueue(SqQueue &Q, QElemType e)
{
	if ((Q.rear + 1) % MAXQSIZE == Q.front)
	{
		printf("队列满");
		system("pause");
		exit(OVERFLOW);
	}
	Q.base[Q.rear] = e;
	Q.rear = (Q.rear + 1) % MAXQSIZE;
	return OK;
}

/*删除*/
Status DeQueue(SqQueue &Q, QElemType &e)
{
	if (Q.front == Q.rear)
	{
		printf("队列为空");
		system("pause");
		return ERROR;
	}
	e = Q.base[Q.front];
	Q.front = (Q.front + 1) % MAXQSIZE;
	return OK;
}

/*判断是否为空*/
Status QueueEmpty(SqQueue &Q)
{
	if (Q.rear == Q.front)
		return 1;
	else
		return 0;
}

/*二叉树基本操作*/
/*输出元素*/
Status Visit(TElemType e)
{
	printf("%c", e);
	return OK;
}

/*先序创建二叉树*/
Status CreateBiTree(BiTree &T) 
{ 
	// 按先序次序输入二叉树中结点的值(一个字符),空格字符表示空树,
	// 构造二叉链表表示的二叉树T。
	char ch;

	scanf_s("%c", &ch);

	if (ch == ' ') T = NULL;

	else 
	{
		if (!(T = (BiTNode *)malloc(sizeof(BiTNode))))
		{
			printf("申请空间失败,程序退出!");
			exit(OVERFLOW);
		}
		T->data = ch;           // 生成根结点
		CreateBiTree(T->lchild);// 构造左子树
		CreateBiTree(T->rchild);// 构造右子树
	}
	return OK;
}

/*先序递归遍历二叉树*/
Status PreOrder(BiTree T)
{
	if (T) 
	{
		
		Visit(T->data);      // 访问结点
		PreOrder(T->lchild); // 遍历左子树 
		PreOrder(T->rchild); // 遍历右子树
	}
	return OK;
}

/*中序递归遍历二叉树*/
Status InOrder(BiTree T)
{
	if (T)
	{
		InOrder(T->lchild); // 遍历左子树 
		Visit(T->data);      // 访问结点
		InOrder(T->rchild); // 遍历右子树
	}
	return OK;
}

/*后序递归遍历二叉树*/
Status LastOrder(BiTree T)
{
	if (T)
	{
		LastOrder(T->lchild); // 遍历左子树 
		LastOrder(T->rchild); // 遍历右子树
		Visit(T->data);      // 访问结点
	}
	return OK;
}

/*先序递归遍历二叉树2*/
Status PreOrderTraverse(BiTree T, Status(*Visit)(TElemType e)) 
{
	// 采用二叉链表存储结构,Visit是对数据元素操作的应用函数,
	// 先序遍历二叉树T的递归算法,对每个数据元素调用函数Visit。
	if (T) 
	{
		if (Visit(T->data))
			if (PreOrderTraverse(T->lchild, Visit))
				if (PreOrderTraverse(T->rchild, Visit)) 
					return OK;
		return ERROR;
	}
	else return OK;
}

/*中序非递归遍历二叉树*/
Status InOrderTraverse(BiTree T, Status(*Visit)(TElemType e)) 
{
	// 采用二叉链表存储结构,Visit是对数据元素操作的应用函数。
	// 中序遍历二叉树T的非递归算法,对每个数据元素调用函数Visit。
	SqStack S;
	BiTree p;

	InitStack(S);  

	Push(S, T);// 根指针进栈

	while (!StackEmpty(S)) 
	{
		while (GetTop(S, p) && p) 
			Push(S, p->lchild);// 向左走到尽头
		Pop(S, p);             // 空指针退栈
		if (!StackEmpty(S)) 
		{// 访问结点,向右一步
			Pop(S, p);
			if (!Visit(p->data)) 
				return ERROR;
			Push(S, p->rchild);
		}
	}
	return OK;
}

/*中序非递归遍历二叉树2*/
Status InOrderTraverse2(BiTree T, Status(*Visit)(TElemType e)) 
{
	// 采用二叉链表存储结构,Visit是对数据元素操作的应用函数。
	// 中序遍历二叉树T的非递归算法,对每个数据元素调用函数Visit。
	SqStack S;
	BiTree p;

	InitStack(S);  

	p = T;

	while (p || !StackEmpty(S)) 
	{
		if (p) 
		{ 
			Push(S, p);  
			p = p->lchild; 
		}//根指针进栈,遍历左子树
		else 
		{//根指针退栈,访问根结点,遍历右子树
			Pop(S, p);
			if (!Visit(p->data)) return ERROR;
			p = p->rchild;
		}
	}
	return OK;
}
//author: 小柳学渣
/*叶子结点个数*/
Status CountLeaf(BiTree T) 
{
	if (T) 
	{
		if ((!T->lchild) && (!T->rchild))
			count++;// 对叶子结点计数
		CountLeaf(T->lchild);
		CountLeaf(T->rchild);
	}
	return OK;
}
//author: 小柳学渣
/*叶子结点个数2*/
int LeafCount_BiTree(BiTree T)
{
	if (!T)
		return 0;//空树没有叶子
	else if (!T->lchild && !T->rchild)
		return 1;//叶子结点_  
	else 
		return LeafCount_BiTree(T->lchild) + LeafCount_BiTree(T->rchild);//左子树的叶子数加上右子树的叶子数_
}

/*度数为1的结点个数*/
Status Count_1(BiTree T)
{
	if (T)
	{
		if (((T->lchild) && (!T->rchild))||((!T->lchild) && (T->rchild)))
			count++;// 对度数为1的结点计数
		Count_1(T->lchild);
		Count_1(T->rchild);
	}
	return OK;
}

/*度数为2的结点个数*/
Status Count_2(BiTree T)
{
	if (T)
	{
		if (((T->lchild) && (T->rchild)))
			count++;// 对度数为2的结点计数
		Count_2(T->lchild);
		Count_2(T->rchild);
	}
	return OK;
}
//author: 小柳学渣
/*深度*/
int Depth(BiTree T) 
{
	int depthval, m, n;

	if (!T)    
		depthval = 0;
	else 
	{
		m = Depth(T->lchild);
		n = Depth(T->rchild);
		depthval = 1 + (m > n ? m : n);
	}
	return depthval;
}
//author: 小柳学渣
/*所有结点个数*/
Status CountAll(BiTree T)
{
	if (T)
	{
		count++;//对结点计数
		CountAll(T->lchild);
		CountAll(T->rchild);
	}
	return OK;
}
//author: 小柳学渣
/*按层遍历*/
void BFSTraverse(BiTree T) 
{
	BiTree p;
	LinkQueue Q;//链队列
	//SqQueue Q;//循环队列

	InitQueue(Q);// 置空的辅助队列Q
	if (T)  
		EnQueue(Q, T);// 根结点入队列
	while (!QueueEmpty(Q)) 
	{
		DeQueue(Q, p);// 队头元素出队并置为p
		Visit(p->data);
		if (p->lchild)
			EnQueue(Q, p->lchild);// 左子树根入队列
		if (p->rchild)
			EnQueue(Q, p->rchild);// 右子树根入队列
	}
}
 
/*主函数*/
int main()
{
	int choice;
	BiTree T;

	printf("创建二叉树(空格代表空):\n");
	CreateBiTree(T);

	while (1)
	{
		printf("1、递归先序遍历\n");
		printf("2、递归中序遍历\n");
		printf("3、递归后序遍历\n");
		printf("4、非递归中序遍历\n");
		printf("5、求叶子结点个数\n");
		printf("6、求度数为1的结点个数\n");
		printf("7、求度数为2的结点个数\n");
		printf("8、求深度\n");
		printf("9、求所有结点个数\n");
		printf("10、按层遍历\n");
		printf("0、退出\n");

		printf("请选择:");
		scanf_s("%d", &choice);
		switch (choice)
		{
		case 1:
			/*1*/
			/*PreOrder(T);
			break;*/

			/*2*/
			PreOrderTraverse(T, Visit);
			break;
		case 2:
			InOrder(T);
			break;
		case 3:
			LastOrder(T);
			break;
		case 4:
			/*1*/
			InOrderTraverse(T, Visit);
			break;

			/*2*/
			/*InOrderTraverse2(T, Visit);
			break;*/
		case 5:
			/*1*/
			/*count = 0;
			CountLeaf(T);
			printf("叶子结点个数为:%d", count);
			break;*/

			/*2*/
			printf("叶子结点个数为:%d", LeafCount_BiTree(T));
			break;
		case 6:
			count = 0;
			Count_1(T);
			printf("度数为1的结点个数为:%d", count);
			break;
		case 7:
			count = 0;
			Count_2(T);
			printf("度数为2的结点个数为:%d", count);
			break;
		case 8:
			printf("深度为:%d", Depth(T));
			break;
		case 9:
			count = 0;
			CountAll(T);
			printf("所有结点个数为:%d", count);
			break;
		case 10:
			BFSTraverse(T);
			break;
		case 0:
			exit(0);
		default:
			printf("您的输入有误,请重新输入!");
		}
		printf("\n\n");
	}
	return 0;
}

线索二叉树.cpp

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

typedef char TElemType;
typedef int Status;

#define OK 1
#define ERROR 0
#define OVERFLOW 0

typedef enum PointerTag
{
	Link,
	Thread
};

typedef struct BiThrNode
{
	TElemType data;
	struct BiThrNode *lchild, *rchild;
	PointerTag LTag, RTag;
}BiThrNode,*BiThrTree;

BiThrTree pre;

/*输出元素*/
Status Visit(TElemType e)
{
	printf("%c", e);
	return OK;
}

Status CreateBiThrTree(BiThrTree &T)
{
	char ch;
	scanf_s("%c", &ch);

	if (ch == ' ')
	{
		T = NULL;
	}
	else
	{
		T = (BiThrNode *)malloc(sizeof(BiThrNode));
		T->data = ch;
		T->LTag = Link;
		T->RTag = Link;

		CreateBiThrTree(T->lchild);
		CreateBiThrTree(T->rchild);
	}
	return OK;
}

Status InOrderTraverse_Thr(BiThrTree T, Status(*Visit)(TElemType)) 
{
	BiThrTree p;

	p = T->lchild; // p指向根结点
	while (p != T) 
	{// 空树或遍历结束时,p==T
		while (p->LTag == Link) 
			p = p->lchild;
		if (!Visit(p->data)) 
			return ERROR; // 访问其左子树为空的结点
		while (p->RTag == Thread && p->rchild != T) 
		{
			p = p->rchild;  
			Visit(p->data); // 访问后继结点
		}
		p = p->rchild; // p进至其右子树根
	}
	return OK;
}

void InThreading(BiThrTree p) //中序遍历进行中序线索化
{
	if (p) 
	{
		InThreading(p->lchild); // 左子树线索化
		if (!p->lchild) // 建前驱线索
		{
			p->LTag = Thread;  
			p->lchild = pre;
		}
		if (!pre->rchild) // 建后继线索
		{
			pre->RTag = Thread;  
			pre->rchild = p;
		}
		pre = p; // 保持pre指向p的前驱
		InThreading(p->rchild); // 右子树线索化
	}
}

Status InOrderThreading(BiThrTree &Thrt, BiThrTree T) 
{
	if (!(Thrt = (BiThrTree)malloc(sizeof(BiThrNode)))) 
		exit(OVERFLOW);
	Thrt->LTag = Link; 
	Thrt->RTag = Thread; // 建头结点
	Thrt->rchild = Thrt; // 右指针回指
	if (!T) 
		Thrt->lchild = Thrt; // 若二叉树空,则左指针回指
	else 
	{
		Thrt->lchild = T;    
		pre = Thrt;
		InThreading(T); //中序遍历进行中序线索化
		pre->rchild = Thrt;  
		pre->RTag = Thread; // 最后一个结点线索化
		Thrt->rchild = pre;
	}
	return OK;
}

Status InPre_(BiThrNode *p, BiThrNode *pre ,BiThrNode *succ)
{
	BiThrNode *q;

	if (p->LTag == 1)  
pre = p->lchild;/*直接利用线索*/
	else
	{
		for (q = p->lchild; q->RTag == 0; q = q->rchild);
		pre = q;/* 在p的左子树中查找“最右下端”结点 */
	}
	if (p->RTag == 1)  
succ = p->rchild;/*直接利用线索*/
	else
	{
		for (q = p->rchild; q->LTag == 0; q = q->lchild);
		succ = q;/*在p的右子树中查找“最左下端”结点*/
	}
	return OK;
}

int main()
{
	BiThrTree Thrt, T = NULL;

	printf("创建二叉树(空格代表空):\n");
	CreateBiThrTree(T);
	InOrderThreading(Thrt, T);
	printf("中序遍历输出结果为: ");
	InOrderTraverse_Thr(T, Visit);
	printf("\n");
    return 0;
}

赫夫曼树(哈夫曼树)
赫夫曼编码(哈夫曼编码)

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>

typedef struct
{
	unsigned int weight;
	unsigned int parent, lchild, rchild;
}HTNode, *HuffmanTree;

typedef char **HuffmanCode;

void Select(HuffmanTree HT, int end, int &s1, int &s2)//从1到end之间选择最小的2个元素的下标
{
	int i = 1;
	unsigned int min1, min2;//min1和min2存放parent为0的最小的2个元素

	while (HT[i].parent != 0 && i <= end)//寻找第一个未访问的元素下标
	{
		i++;
	}
	if (i == end + 1)
	{
		return;
	}
	s1 = i;
	min1 = HT[i].weight;
	i++;
	while (HT[i].parent != 0 && i <= end)//寻找第二个未访问的元素下标
	{
		i++;
	}
	if (i == end + 1)
	{
		return;
	}
	s2 = i;
	min2 = HT[i].weight;
	i++;
	if (min1 > min2)
	{
		unsigned int temp = min1;
		min1 = min2;
		min2 = temp;
		temp = s1;
		s1 = s2;
		s2 = temp;
	}
	for (; i <= end; i++)
	{
		if (HT[i].parent == 0)
		{
			if (HT[i].weight < min1)
			{
				s2 = s1;
				s1 = i;
				min2 = min1;
				min1 = HT[i].weight;
			}
			else if (HT[i].weight < min2)
			{
				s2 = i;
				min2 = HT[i].weight;
			}
		}
	}
}

void HuffmanCoding(HuffmanTree &HT, HuffmanCode &HC, int *w, int n)
{
	// w存放n个字符的权值(均>0),构造哈夫曼树HT,并求出n个字符的哈夫曼编码HC。
	int i, j, m, s1 = 0, s2 = 0, start;
	char *cd;
	unsigned int c, f;
	HuffmanTree p;

	if (n <= 1)
	{
		return;
	}
	m = 2 * n - 1;
	HT = (HuffmanTree)malloc((m + 1) * sizeof(HTNode));// 0号单元未用
	for (i = 1; i <= n; i++)
	{
		//初始化
		HT[i].weight = w[i - 1];
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}
	for (i = n + 1; i <= m; i++)
	{
		//初始化
		HT[i].weight = 0;
		HT[i].parent = 0;
		HT[i].lchild = 0;
		HT[i].rchild = 0;
	}
	printf("\n哈夫曼树的构造过程如下所示:\n");
	printf("HT初态:\n  结点  weight  parent  lchild  rchild");
	for (i = 1; i <= m; i++)
		printf("\n%4d%8d%8d%8d%8d", i, HT[i].weight, HT[i].parent, HT[i].lchild, HT[i].rchild);
	printf("\t按任意键,继续 ...");
	_getch();
	for (i = n + 1; i <= m; ++i)
	{
		// 建哈夫曼树
		// 在HT[1..i-1]中选择parent为0且weight最小的两个结点,其序号分别为s1和s2。
		Select(HT, i - 1, s1, s2);
		HT[s1].parent = i;
		HT[s2].parent = i;
		HT[i].lchild = s1;
		HT[i].rchild = s2;
		HT[i].weight = HT[s1].weight + HT[s2].weight;
		printf("\nselect: s1=%d   s2=%d\n", s1, s2);
		printf("  结点  weight  parent  lchild  rchild");
		for (j = 1; j <= i; j++)
			printf("\n%4d%8d%8d%8d%8d", j, HT[j].weight, HT[j].parent, HT[j].lchild, HT[j].rchild);
		printf("\t按任意键,继续 ...");
		_getch();
	}
	printf("\n\n");

	//--- 从叶子到根逆向求每个字符的哈夫曼编码 ---

	HC = (HuffmanCode)malloc((n + 1) * sizeof(char*));/*分配n个字符编码的头指针向量*/
	cd = (char *)malloc(n * sizeof(char));    // 分配求编码的工作空间
	cd[n - 1] = '\0';                         // 编码结束符。
	for (i = 1; i <= n; ++i)
	{                                         // 逐个字符求哈夫曼编码
		start = n - 1;                        // 编码结束符位置
		for (c = i, f = HT[i].parent; f != 0; c = f, f = HT[f].parent)// 从叶子到根逆向求编码
			if (HT[f].lchild == c)
				cd[--start] = '0';
			else
				cd[--start] = '1';
		HC[i] = (char *)malloc((n - start) * sizeof(char));// 为第i个字符编码分配空间
		strcpy_s(HC[i], sizeof(HC[i])+1, &cd[start]);// 从cd复制编码(串)到HC
	}
	free(cd);// 释放工作空间
}

int main()
{
	int a[8] = { 5,29,7,8,14,23,3,11 };
	HuffmanTree ht;
	HuffmanCode hc;

	HuffmanCoding(ht, hc, a, 8);

	printf("赫夫曼编码为:\n");
	for (int i = 1; i <= 8; i++)
	{
		printf("%d\t%s\n",ht[i].weight,hc[i]);
	}
	printf("\n");
	return 0;
}

猜你喜欢

转载自blog.csdn.net/l503301397/article/details/86677993