目录
5.3.1 二叉树的遍历
1.function.h
#include <stdio.h>
#include <stdlib.h>
typedef char BiElemType;
//二叉树结点的结构体定义
typedef struct BiTNode {
BiElemType c;//c就是书上的data
struct BiTNode* lchild;
struct BiTNode* rchild;
}BiTNode, * BiTree;
//辅助队列结点的结构体定义
typedef struct tag {
BiTree p;//树的某一个结点的地址值
struct tag* pnext;
}tag_t, * ptag_t;
//栈的相关数据结构
#define MaxSize 50
typedef BiTree ElemType;
typedef struct {
ElemType data[MaxSize];
int top;
}SqStack;
//声明放在头文件中的目的:声明一次即可,在其他文件中要引用函数时,#include 头文件即可,不用多次声明
void InitStack(SqStack& S);
bool StackEmpty(SqStack& S);
bool Push(SqStack& S, ElemType x);
bool Pop(SqStack& S, ElemType& x);
bool GetTop(SqStack& S, ElemType& x);
//队列的相关数据结构(链队)
typedef struct LinkNode {
ElemType data;
struct LinkNode* next;
}LinkNode;
//单独定义队头、队尾的指针
typedef struct {
LinkNode* front, * rear;
}LinkQueue;
void InitQueue(LinkQueue& Q);
bool IsEmpty(LinkQueue Q);
void EnQueue(LinkQueue& Q, ElemType x);
bool DeQueue(LinkQueue& Q, ElemType& x);
2. main.cpp
#include "function.h"
#define _CRT_SECURE_NO_WARNINGS
//递归实现
//abdhiejcfg
void preOrder(BiTree p)
{
if (p != NULL)
{
putchar(p->c);//等价于visit函数
preOrder(p->lchild);
preOrder(p->rchild);
}
}
//中序遍历 hdibjeafcg
void InOrder(BiTree p)
{
if (p != NULL)
{
InOrder(p->lchild);
putchar(p->c);
InOrder(p->rchild);
}
}
//hidjebfgca
void PostOrder(BiTree p)
{
if (p != NULL)
{
PostOrder(p->lchild);
PostOrder(p->rchild);
putchar(p->c);
}
}
//中序遍历非递归,非递归执行效率更高,考的概率很低
void InOrder2(BiTree T)
{
SqStack S;
InitStack(S); BiTree p = T;//p是遍历指针
while (p || !StackEmpty(S))//p非空或者栈非空
{
if (p)
{
Push(S, p);
p = p->lchild;//一路向左,找到最左结点
}
else {//找到最左结点后,接着要依次访问其父结点及其右兄弟(中序遍历)
Pop(S, p); putchar(p->c);//putchar(p->c)相当于visit(p)函数
p = p->rchild;
}
}
}
//层次遍历,广度优先遍历
void LevelOrder(BiTree T)
{
LinkQueue Q;
InitQueue(Q);
BiTree p = T;
EnQueue(Q, T);//树根入队
while (!IsEmpty(Q))
{
DeQueue(Q, p);
putchar(p->c);
if (p->lchild != NULL)
EnQueue(Q, p->lchild);
if (p->rchild != NULL)
EnQueue(Q, p->rchild);
}
}
//层序建树——借助逻辑上的辅助队列
int main() {
BiTree tree = NULL;//树的根结点
BiTree tpnew;//指向树的新结点的指针
ptag_t phead = NULL, ptail = NULL,listpnew = NULL, pcur = NULL;
char c;
//辅助队列中的队头,队尾结点,指向新结点的listpnew,指向当前插入位置的父结点的pcur
//abcdefg
while (scanf_s("%c", &c) != EOF) {
if ('\n' == c) {
break;//结束循环
}
//分配空间
tpnew = (BiTree)calloc(1, sizeof(BiTNode));//给树结点分配空间
tpnew->c = c;//输入的元素放入树结点中
listpnew = (ptag_t)calloc(1, sizeof(tag_t));//给队列结点分配空间
listpnew->p = tpnew;//树的结点地址放入队列结点中
if (NULL == tree) {
tree = tpnew;
phead = listpnew;
ptail = listpnew;
pcur = listpnew;//pcur始终指向插入位置的父结点
continue;//继续下一轮循环
}
else {
ptail->pnext = listpnew;
ptail = listpnew;//队列中使用尾插法
}
if (NULL == pcur->p->lchild) {//通过队列找到树中结点
pcur->p->lchild = tpnew;
}
else if (NULL == pcur->p->rchild) {
pcur->p->rchild = tpnew;
pcur = pcur->pnext;//以a为根节点的左右子树已经插好,逻辑上需要将a出队,插入位置的父节点由a变为了b,所以pcur要后移
}
}
InOrder(tree);
printf("\n");
PostOrder(tree);
printf("\n");
LevelOrder(tree);
}
3. stack.cpp
#include "fun.h"
void InitStack(SqStack& S)
{
S.top = -1;
}
bool StackEmpty(SqStack& S)
{
if (S.top == -1)
return true;
else
return false;
}
//入栈
bool Push(SqStack& S, ElemType x)
{
if (S.top == MaxSize - 1)
{
return false;
}
S.data[++S.top] = x;
return true;
}
//出栈
bool Pop(SqStack& S, ElemType& x)
{
if (-1 == S.top)
return false;
x = S.data[S.top--];
return true;
}
//读取栈顶元素
bool GetTop(SqStack& S, ElemType& x)
{
if (-1 == S.top)
return false;
x = S.data[S.top];
return true;
}
4. queue.cpp
#include "fun.h"
//带头结点的链队——头结点的下一个节点才有数据
//初始化
void InitQueue(LinkQueue& Q)
{
Q.front = Q.rear = (LinkNode*)malloc(sizeof(LinkNode));
Q.front->next = NULL;
}
//判空
bool IsEmpty(LinkQueue Q)
{
if (Q.front == Q.rear)
return true;
else
return false;
}
//入队、出队操作当作链表处理
//入队——尾插法
void EnQueue(LinkQueue& Q, ElemType x)
{
LinkNode* s = (LinkNode*)malloc(sizeof(LinkNode));
s->data = x; s->next = NULL;
Q.rear->next = s;
Q.rear = s;
}
//出队——头部删除法
bool DeQueue(LinkQueue& Q, ElemType& x)
{
if (Q.front == Q.rear) return false;//队空不出
LinkNode* p = Q.front->next;//头结点什么都没存,所以头结点的下一个节点才有数据(带头结点的链队)
x = p->data;
Q.front->next = p->next;
if (Q.rear == p)
Q.rear = Q.front;
free(p);
return true;
}
5.3.2 线索二叉树
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char ElemType;
typedef struct ThreadNode {
ElemType data;
struct ThreadNode* lchild, * rchild;
int ltag, rtag;
}ThreadNode, * ThreadTree;
//手工建线索树,总计5个结点
void BulidThreadTree(ThreadTree& T)
{
ThreadTree arr[5];
int i;
for (i = 0; i < 5; i++)
{
arr[i] = (ThreadTree)malloc(sizeof(ThreadNode));
memset(arr[i], 0, sizeof(ThreadNode));
arr[i]->data = 'A' + i;
}
arr[0]->lchild = arr[1];
arr[0]->rchild = arr[2];
arr[1]->rchild = arr[3];
arr[2]->lchild = arr[4];
T = arr[0];
}
void InThread(ThreadTree& p, ThreadTree& pre)
{
if (p != NULL) {
InThread(p->lchild, pre);//递归找树的左孩子
if (p->lchild == NULL) {//左边为NULL,填写当前结点的前驱
p->lchild = pre;
p->ltag = 1;
}
if (pre != NULL && pre->rchild == NULL) {
//pre节点右孩子为NULL,就让其指向后继节点,而后继结点刚好就是p
pre->rchild = p;
pre->rtag = 1;
}
pre = p;
InThread(p->rchild, pre);
}
}
void CreateInThread(ThreadTree T)
{
ThreadTree pre = NULL;//使用辅助指针pre
if (T != NULL) {
InThread(T, pre);
pre->rchild = NULL;
pre->rtag = 1;
}
}
//求中序序列下的第一个结点
ThreadNode* Firstnode(ThreadNode* p)
{
while (p->ltag == 0)
p = p->lchild;
return p;
}
//p在中序序列下的后继结点
int main()
{
ThreadTree T;
ThreadTree p;
BulidThreadTree(T);
CreateInThread(T);//构建线索二叉树
p = Firstnode(T);
printf("最左下结点值为 %c\n", p->data);
}
5.5.1 二叉排序树
#include <stdio.h>
#include <stdlib.h>
typedef int KeyType;//关键字类型
//BST结点定义
typedef struct BSTNode {
KeyType key;
struct BSTNode* lchild, * rchild;
}BSTNode, *BiTree;
//插入
int BST_Insert(BiTree& T, KeyType k) {
if (NULL == T) {
T = (BiTree)malloc(sizeof(BSTNode));
T->key = k;
T->lchild = T->rchild = NULL;
return 1;
}
else if (k == T->key) {
return 0;
}
else if (k < T->key) {
return BST_Insert(T->lchild, k);
}
else {
return BST_Insert(T->rchild, k);
}
}
//构造BST
void Creat_BST(BiTree& T, KeyType str[], int n) {//str[]为关键字序列,n为关键字个数
T = NULL;//初始时T为空树
int i = 0;//关键字序列的下标,用来取关键字插入到BST中
while (i < n) {//依次将每个关键字插入到BST中
BST_Insert(T, str[i]);
i++;
}
}
//查找(非递归)
BSTNode* BST_Search(BiTree T, KeyType k, BiTree& p) {
p == NULL;
while (T != NULL && T->key != k) {
if (k < T->key) {
T = T->lchild;
p = T;
}
else {
T = T->rchild;
p = T;
}
}
return T;
}
//删除
void DeleteNode(BiTree& root, KeyType x) {
if (NULL == root) {
return;
}
if (x < root->key) {
DeleteNode(root->lchild, x);
}
if (x > root->key) {
DeleteNode(root->rchild, x);
}
else {
if (NULL == root->lchild) {
BiTree TNode = root;
root = root->rchild;
free(TNode);
}
else if (NULL == root->rchild) {
BiTree TNode = root;
root = root->lchild;
free(TNode);
}
else {
BiTree TNode = root->lchild;
if (TNode->lchild != NULL) {
TNode = TNode->rchild;
}
root->key = TNode->key;
DeleteNode(root->lchild, TNode->key);
}
}
}
//中序遍历
void InOrder(BiTree T) {
if (T != NULL) {
InOrder(T->lchild);
printf("%3d", T->key);
InOrder(T->rchild);
}
}
int main()
{
BiTree T;
BiTree parent;//存储父亲结点的地址值
BiTree search;
KeyType str[] = { 54,20,66,40,28,79,58 };//将要进入二叉排序树的元素值
Creat_BST(T, str, 7);
InOrder(T);
printf("\n");
search = BST_Search(T, 40, parent);
if (search)
{
printf("找到对应结点,值=%d\n", search->key);
}
else {
printf("未找到对应结点\n");
}
DeleteNode(T, 66);
InOrder(T);
printf("\n");
}