目录
2.思路 利用辅助队列,先把根结点入队,当队列不为空时,出队,并判断左右结点是否为null,不是null则入队,循环往复
一、存储结构
1.顺序存储
(1)定义
typedef int ElemType;
#define MaxSize 10
typedef struct SqTree{
ElemType data[MaxSize];
}SqTree;
(2)初始化
void InitTree(SqTree &T){
for (int i = 1; i < MaxSize; ++i) {
T.data[i] = i;
}
}
(3)打印
void print(SqTree T){
for (int i = 1; i < MaxSize; ++i) {
printf("%d",T.data[i]);
}
printf("\n");
}
2.链式存储(二叉树链式存储)
(1)定义
typedef struct BiTNode{
ElemType data;
struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;
(2)初始化
void InitBiTree(BiTree &BT){
BT = (BiTNode*)malloc(sizeof(BiTNode));
BT->lchild = NULL;
BT->rchild = NULL;
}
(3)创建(一个一个加)
void AddTreeNode(BiTNode *&Node,ElemType e){
if(Node == NULL){ //非头结点
Node = (BiTNode*)malloc(sizeof (BiTNode));
Node->data = e;
Node->lchild = NULL;
Node ->rchild = NULL;
}
Node->data = e;//头结点
}
二、层次建树
1.function.h头文件,存储数据结构定义
//function.h
typedef char BiElemType;
//单个结点
typedef struct BiTNode{
BiElemType c;
struct BiTNode *lchild;
struct BiTNode *rchild;
}BiTNode,*BiTree;
//tag结构体是辅助队列(链队)使用的
typedef struct tag{
BiTree p;
struct tag *pnext;
}tag_t,*ptag_t;
2.创建
int main()
{
BiTree pnew;//用来申请新的树节点
BiTree tree=NULL;//根节点,必须声明为空树
char c;
ptag_t phead=NULL,ptail=NULL,listpnew=NULL,pcur;
//phead队列头,ptail队列尾,listpnew指向链表队列中的新结点,pcur指向新来的元素放在树的哪个位置
while(scanf("%c",&c)){
if (c=='\n') //不存换行符号
{
break;
}
pnew = (BiTree)calloc(1,sizeof (BiTNode));
//calloc() stdlib.h
//申请的空间是1*sizeof(BiTree),两个参数相乘
//and在申请时左右孩子空间也是0了(同时初始化)
//so不用malloc
pnew->c=c;//存数据
//给辅助队列结点申请空间
listpnew= (ptag_t)calloc(1,sizeof(tag_t));
listpnew-> p = pnew;
if(NULL == tree){//树的第一个结点
tree=pnew;//tree指向根节点
phead =listpnew;//一个结点的时候既是头部也是尾部
ptail = listpnew;
pcur = listpnew;//pcur指向父亲结点
}else{//后面的
ptail->pnext = listpnew;
ptail = listpnew;
if(NULL == pcur ->p->lchild) {
pcur ->p->lchild= pnew;
}
else if(NULL == pcur ->p->rchild){
pcur ->p->rchild= pnew;
pcur = pcur ->pnext;
}
}
}
}
三、遍历
1.前序(根左右)(深度优先遍历)
void PreOrder(BiTree BT){
if(BT != NULL){
visit(BT);
PreOrder(BT->lchild);
PreOrder(BT->rchild);
}
}
2.中序(左根右)
//中序遍历
void InOrder(BiTree BT){
if(BT!=NULL) {
PreOrder(BT->lchild);
visit(BT);
PreOrder(BT->rchild);
}
}
3.后序(左右根)
void PostOrder(BiTree BT){
if(BT != NULL){
PostOrder(BT->lchild);
PostOrder(BT->rchild);
visit(BT);
}
}
4、层序遍历
void LevelOrder(BiTree BT) {
LinkQueue Q;
InitQueue(Q);
EnQueue(Q,BT);
BiTree p;//用于输出
while(!isEmpty(Q)){
DeQueue(Q,p);
visit(p);
if(p->lchild != NULL){
EnQueue(Q,p->lchild);
}
if(p->rchild != NULL){
EnQueue(Q,p->lchild);
}
}
}
2.事前准备
创建二叉树,创建queue.cpp和function.h
(1)function.h
#include <stdio.h>
#include <stdlib.h>
typedef char ElemType;
//单个结点
typedef struct BiTNode{
ElemType c;
struct BiTNode *lchild;
struct BiTNode *rchild;
}BiTNode,*BiTree;
//tag结构体是辅助队列(链队)使用的
typedef struct tag{
BiTree p;
struct tag *pnext;
}tag_t,*ptag_t;
typedef BiTree BiElemType;
//队列的链式存储 LinkQueue
//有头尾指针的单链表
//链表
typedef struct LinkNode{
BiElemType data;
struct LinkNode *next;
}LinkNode;
//链表队列
typedef struct {
LinkNode *front,*rear;//队头队尾(链表头、尾)
}LinkQueue;
(2)queue.cpp
#include "function.h"
bool IsEmpty(LinkQueue Q){
return Q.front == Q.rear;
}
void InitQueue(LinkQueue &Q){
Q.front= Q.rear = (LinkNode*)malloc(sizeof (LinkNode));
Q.front->next =NULL;
}
void EnQueue(LinkQueue &Q,BiElemType x){
LinkNode *pnew = (LinkNode*)malloc(sizeof (LinkNode));
pnew ->data = x;
pnew ->next = NULL;//否则无法停止
Q.rear ->next = pnew;//尾指针指向pnew
Q.rear = pnew;//新的尾部
}
bool DeQueue(LinkQueue &Q,BiElemType &x){
if(Q.rear == Q.front){//空的
return false;
}
LinkNode* q = Q.front ->next;//第一个结点
x = q->data;//获取出队的元素值
Q.front->next = q ->next;
if(Q.rear == q){//只剩1个结点
Q.rear = Q.front;
}
free(q);//断链
return true;
}
2.思路
利用辅助队列,先把根结点入队,当队列不为空时,出队,并判断左右结点是否为null,不是null则入队,循环往复
3.代码实现
void LevelOrder(BiTree T){
LinkQueue Q;//辅助队列
InitQueue(Q);
BiTree p;//存储出队结点
EnQueue(Q,T);//树根入队
while(!IsEmpty(Q)){
DeQueue(Q,p);
putchar(p->c);
if(p->lchild){
EnQueue(Q,p->lchild);
}
if(p->rchild){
EnQueue(Q,p->rchild);
}
}
}
四、线索二叉树
1.定义
typedef char ElemType;
typedef struct ThreadNode {
ElemType data;
struct ThreadNode *lchild, *rchild;
int ltag, rtag;
} ThreadNode, *ThreadTree;
2.初始化
void InitThreadTree(ThreadTree &TT) {
TT = (ThreadNode *) malloc(sizeof(ThreadNode));
TT->lchild = NULL;
TT->rchild = NULL;
TT->ltag = 0;
TT->rtag = 0;
}
3.插入结点
void AddTreeNode(ThreadNode *&Node, ElemType e) {
if (Node == NULL) { //非头结点
Node = (ThreadNode *) malloc(sizeof(ThreadNode));
Node->data = e;
Node->lchild = NULL;
Node->rchild = NULL;
Node ->ltag = 0;
Node ->rtag = 0;
}
Node->data = e;//头结点
}
4.土办法找中序遍历的前驱(二叉树)
attn:全局变量是在main()之外,p指针要指向结点,不能直接赋值
全局变量
BiTNode *p;
BiTNode *pre=NULL;
BiTNode *final=NULL;
//函数
void visit(BiTNode *q){
if(q!=NULL){
//指针引用直接 变量名
if(q == p) final = pre;
else pre = q;
}
}
void InOrderFindPre(BiTree TT){
if(TT!=NULL){
InOrderFindPre(TT->lchild);
visit(TT);
InOrderFindPre(TT->rchild);
}
}
5.利用线索二叉树(中序找前驱)
//全局变量
ThreadNode *p;
ThreadNode *pre = NULL;
//函数
void InThreadVisit(ThreadNode *q) {
if (q->lchild == NULL) {//左孩子为null,指向前驱
q->lchild = pre;//左孩子指向pre
q->ltag = 1;
}
if (pre != NULL && pre->rchild == NULL ) {//指后继
pre->rchild = q;
pre->rtag = 1;
}
pre = q;//访问下一个结点
}
//利用线索二叉树
//结果剩下最后一个结点没有线索化
void InThread(ThreadTree &TT) {
if (TT != NULL) {//左孩子为null
InThread(TT->lchild);
InThreadVisit(TT);
InThread(TT->rchild);
}
}
void CreateInThread(ThreadTree &T) {
pre = NULL;
if (T != NULL) {
InThread(T);
pre->rchild = NULL;//完善最后一个右节点
pre->rtag = 1;
}
}
6.前序找前驱
//全局变量
ThreadNode *p;
ThreadNode *pre = NULL;
//函数
void PreThreadVisit(ThreadTree &q) {
if (q->lchild == NULL) {
q->lchild = pre;
q->ltag = 1;
}
if (pre != NULL && pre->rchild == NULL) {
pre->rchild = q;
pre->ltag = 1;
}
pre = q;
}
void PreThread(ThreadTree &q) {
if (q != NULL) {
PreThreadVisit(q);
if (q->ltag == 0) { //if此结点的左孩子的前驱正好是此结点,则会发生死循环,so用tag判断
//so该结点左孩子的前驱不是该结点时即该结点左孩子为空
PreThread(q->lchild);
}
PreThread(q->rchild);
}
}
void CreatePreThread(ThreadTree &TT) {
pre = NULL;
if (TT != NULL) {
PreThread(TT);
if(TT->rchild == NULL) {
TT->rtag = 1;
}
}
}
五、树的存储结构
1.双亲表示法
typedef char ElemType;
#define MAX_TREE_SIZE 100
typedef struct {//结点
ElemType data;
int parent;
}PTNode;
typedef struct{//整体
PTNode nodes[MAX_TREE_SIZE];
int n;
}PTree;
2.孩子兄弟表示法
typedef struct CSNode{
ElemType data;
struct CSNode *lchild,*nextsibling;
}CSNode,*CSTree;
六、并查集
1.创建
#define SIZE 100
int UFSets[SIZE];
2.初始化
void Initial(int S[]){
for (int i = 0; i < SIZE; ++i) {
S[i] = -1;
}
}
3.增加元素
void add(int S[]){
S[1] = 0;
for (int i = 2; i < 4; ++i) {
S[i] = -1;
}
for (int i = 4; i < 6; ++i) {
S[i] = 1;
}
S[6] = 2;
for (int i = 7; i < 10; ++i) {
S[i] = 3;
}
for (int i = 10; i < 12; ++i) {
S[i] = 4;
}
S[12] = 7;
}
4.查
int Find(int S[],int x){
while(S[x] >= 0){//x的父节点不是-1,x不是根节点
x = S[x];
}
return x;//x的根的下标
}
5.并
void Union(int S[],int Root1,int Root2){
if(Root1 == Root2) return;
S[Root2] = Root1;//2到1下
}
6.优化
(1)优化Union
//增加元素
void addPer(int S[]) {
S[0] = -6;
S[2] = -2;
S[3] = -5;
S[1] = 0;
for (int i = 4; i < 6; ++i) {
S[i] = 1;
}
S[6] = 2;
for (int i = 7; i < 10; ++i) {
S[i] = 3;
}
for (int i = 10; i < 12; ++i) {
S[i] = 4;
}
S[12] = 7;
}
void UnionPer(int S[], int Root1, int Root2) {
if (Root1 == Root2) return;
if (S[Root2] > S[Root1]) {//-2>-6 2浅 让2 归1
S[Root1] += S[Root2];
S[Root2] = Root1;
} else {
S[Root2] += S[Root1];
S[Root1] = Root2;
}
}
(2)优化Find
int FindPer(int S[],int x){
//先找到根结点下标,再修改
int root = x;
while(S[root] >= 0){
root = S[root];
}
while(x!= root){
int t = S[x];//记录真实父节点
S[x] = root;
x = t;
}
return root;
}