?? 002.cpp
字號:
#include<stdio.h>
#include<malloc.h>
#include<math.h>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
typedef int Status ;
//函數狀態類型
typedef int ElemType ;
//二叉樹結點數據類型為整型
#define FORMAT "%d "
//輸出格式與ElemType對應
void RandomHundred(int ran[100])
//產生100個不大于100且各不相同的整數,存放在ran[100]中
{int i,temp,ransubscript ;
//temp用于交換,ransubscript為隨機下標
for(i=1;i<101;++i)ran[i-1]=i ;
//先把1-100按順序放入數組中
for(i=100;i>0;--i)
{ransubscript=rand()%i ;
//產生隨機下標
temp=ran[i-1];
ran[i-1]=ran[ransubscript];
ran[ransubscript]=temp ;
//交換ran[i-1]與ran[ransubscript]}}
typedef struct BSTNode
{ElemType data ;
int bf ;
/*結點的平衡因子*/
struct BSTNode*lchild,*rchild ;
/* 左、右孩子指針 */}BSTNode,*BSTree ;
#define EQ(a,b)((a)==(b))
#define LT(a,b)((a)<(b))
#define LH +1 /* 左高 */
#define EH 0 /* 等高 */
#define RH -1 /* 右高 */
void R_Rotate(BSTree*p)
{/* 對以*p為根的二叉排序樹作右旋處理,處理之后p指向新的樹根結點,即旋轉 */
/* 處理之前的左子樹的根結點。算法9.9 */
BSTree lc ;
lc=(*p)->lchild ;
/* lc指向p的左子樹根結點 */
(*p)->lchild=lc->rchild ;
/* lc的右子樹掛接為p的左子樹 */
lc->rchild=*p ;
*p=lc ;
/* p指向新的根結點 */}
void L_Rotate(BSTree*p)
{/* 對以*p為根的二叉排序樹作左旋處理,處理之后p指向新的樹根結點,即旋轉 */
/* 處理之前的右子樹的根結點。算法9.10 */
BSTree rc ;
rc=(*p)->rchild ;
/* rc指向p的右子樹根結點 */
(*p)->rchild=rc->lchild ;
/* rc的左子樹掛接為p的右子樹 */
rc->lchild=*p ;
*p=rc ;
/* p指向新的根結點 */}
void LeftBalance(BSTree*T)
{/* 對以指針T所指結點為根的二叉樹作左平衡旋轉處理,本算法結束時, */
/* 指針T指向新的根結點。算法9.12 */
BSTree lc,rd ;
lc=(*T)->lchild ;
/* lc指向*T的左子樹根結點 */
switch(lc->bf)
{ /* 檢查*T的左子樹的平衡度,并作相應平衡處理 */
case LH :
/* 新結點插入在*T的左孩子的左子樹上,要作單右旋處理 */
(*T)->bf=lc->bf=EH ;
R_Rotate(T);
break ;
case RH :
/* 新結點插入在*T的左孩子的右子樹上,要作雙旋處理 */
rd=lc->rchild ;
/* rd指向*T的左孩子的右子樹根 */
switch(rd->bf)
{ /* 修改*T及其左孩子的平衡因子 */
case LH :
(*T)->bf=RH ;
lc->bf=EH ;
break ;
case EH :
(*T)->bf=lc->bf=EH ;
break ;
case RH :
(*T)->bf=EH ;
lc->bf=LH ;
break ;}
rd->bf=EH ;
L_Rotate(&(*T)->lchild);
/* 對*T的左子樹作左旋平衡處理 */
R_Rotate(T);
/* 對*T作右旋平衡處理 * }}
void RightBalance(BSTree*T)
{/* 對以指針T所指結點為根的二叉樹作右平衡旋轉處理,本算法結束時, */
/* 指針T指向新的根結點 */
BSTree rc,rd ;
rc=(*T)->rchild ;
/* rc指向*T的右子樹根結點 */
switch(rc->bf)
{/* 檢查*T的右子樹的平衡度,并作相應平衡處理 */
case RH :
/* 新結點插入在*T的右孩子的右子樹上,要作單左旋處理 */
(*T)->bf=rc->bf=EH ;
L_Rotate(T);
break ;
case LH :
/* 新結點插入在*T的右孩子的左子樹上,要作雙旋處理 */
rd=rc->lchild ;
/* rd指向*T的右孩子的左子樹根 */
switch(rd->bf)
{/* 修改*T及其右孩子的平衡因子 */
case RH :
(*T)->bf=LH ;
rc->bf=EH ;
break ;
case EH :
(*T)->bf=rc->bf=EH ;
break ;
case LH :
(*T)->bf=EH ;
rc->bf=RH ;
break ;}
rd->bf=EH ;
R_Rotate(&(*T)->rchild);
/* 對*T的右子樹作右旋平衡處理 */
L_Rotate(T);
/* 對*T作左旋平衡處理 */}}
Status InsertAVL(BSTree*T,ElemType e,Status*taller)
{/* 若在平衡的二叉排序樹T中不存在和e有相同關鍵字的結點,則插入一個 */
/* 數據元素為e的新結點,并返回1,否則返回0。若因插入而使二叉排序樹 */
/* 失去平衡,則作平衡旋轉處理,布爾變量taller反映T長高與否。算法9.11 */
if(!*T)
{/* 插入新結點,樹“長高”,置taller為TRUE */
*T=(BSTree)malloc(sizeof(BSTNode));
(*T)->data=e ;
(*T)->lchild=(*T)->rchild=NULL ;
(*T)->bf=EH ;
*taller=TRUE ;}
else
{if(EQ(e,(*T)->data))
{/* 樹中已存在和e有相同關鍵字的結點則不再插入 */
*taller=FALSE ;
return FALSE ;}
if(LT(e,(*T)->data))
{/* 應繼續在*T的左子樹中進行搜索 */
/* 未插入 */
if(!InsertAVL(&(*T)->lchild,e,taller))return FALSE ;
/* 已插入到*T的左子樹中且左子樹“長高” */
/* 檢查*T的平衡度 */
if(*taller)switch((*T)->bf)
{case LH :
/* 原本左子樹比右子樹高,需要作左平衡處理 */
LeftBalance(T);
*taller=FALSE ;
break ;
case EH :
/* 原本左、右子樹等高,現因左子樹增高而使樹增高 */
(*T)->bf=LH ;
*taller=TRUE ;
break ;
case RH :
(*T)->bf=EH ;
/* 原本右子樹比左子樹高,現左、右子樹等高 */
*taller=FALSE ;}}
else
{/* 應繼續在*T的右子樹中進行搜索 */
/* 未插入 */
if(!InsertAVL(&(*T)->rchild,e,taller))return FALSE ;
/* 已插入到T的右子樹且右子樹“長高” */
/* 檢查T的平衡度 */
if(*taller)switch((*T)->bf)
{case LH :
(*T)->bf=EH ;
/* 原本左子樹比右子樹高,現左、右子樹等高 */
*taller=FALSE ;
break ;
case EH :
/* 原本左、右子樹等高,現因右子樹增高而使樹增高 */
(*T)->bf=RH ;
*taller=TRUE ;
break ;
case RH :
/* 原本右子樹比左子樹高,需要作右平衡處理 */
RightBalance(T);
*taller=FALSE ;}}}
return TRUE ;}
typedef BSTree SElemType;//這個很重要,定義棧的元素類型為二叉樹結點指針BSTree
//棧的順序存儲表示
//SElemType為棧元素,由用戶在主函數中定義
#define STACK_INIT_SIZE 100 /* 存儲空間初始分配量 */
#define STACKINCREMENT 10 /* 存儲空間分配增量 */
typedef struct SqStack
{SElemType *base; /* 在棧構造之前和銷毀之后,base的值為NULL */
SElemType *top; /* 棧頂指針 */
int stacksize; /* 當前已分配的存儲空間,以元素為單位 */
}SqStack; /* 順序棧 */
//順序棧(存儲結構由SqStack.h定義)的基本操作
Status InitStack(SqStack *S)
{ /* 構造一個空棧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 StackEmpty(SqStack S)
{ /* 若棧S為空棧,則返回TRUE,否則返回FALSE */
if(S.top==S.base)
return TRUE;
else
return FALSE;}
Status Push(SqStack *S,SElemType e)
{ /* 插入元素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)
{ /* 若棧不空,則刪除S的棧頂元素,用e返回其值,并返回OK;否則返回ERROR */
if((*S).top==(*S).base)
return ERROR;
*e=*--(*S).top;
return OK;}
void PreOrderTraverse(BSTree T,Status(*Visit)(ElemType e))
//非遞歸先序遍歷二叉樹
{BSTree p,e ;
SqStack S ;
InitStack(&S);
p=T ;
while(p||!StackEmpty(S))
{//遍歷左子樹
while(p)
{ (*Visit)(p->data);
Push(&S,p);
p=p->lchild ;}
//通過下一次循環中的內嵌while實現右子樹遍歷
if(!StackEmpty(S))
{Pop(&S,&e);
p=e->rchild ;}}}
void InOrderTraverse(BSTree T,Status(*Visit)(ElemType e))
{/* 初始條件: 二叉樹T存在,Visit是對結點操作的應用函數 */
/* 操作結果: 中序遞歸遍歷T,對每個結點調用函數Visit一次且僅一次 */
if(T)
{InOrderTraverse(T->lchild,(*Visit));
/* 先中序遍歷左子樹 */
(*Visit)(T->data);
/* 再訪問根結點 */
InOrderTraverse(T->rchild,(*Visit));
/* 最后中序遍歷右子樹 */}}
void PostOrderTraverse(BSTree T,Status(*Visit)(ElemType e))
{/* 初始條件: 二叉樹T存在,Visit是對結點操作的應用函數 */
/* 操作結果: 后序遞歸遍歷T,對每個結點調用函數Visit一次且僅一次 */
/* T不空 */
if(T)
{PostOrderTraverse(T->lchild,(*Visit));
/* 先后序遍歷左子樹 */
PostOrderTraverse(T->rchild,(*Visit));
/* 再后序遍歷右子樹 */
(*Visit)(T->data);
/* 最后訪問根結點 */}}
/*輸出元素*/
Status PrintElement(ElemType e)
{printf(FORMAT,e);
return OK ;}
#include"RandomHundred.c"
//功能模塊1-void RandomHundred(int ran[100]);產生100個不大于100且各不相同的整數,存放在ran[100]中
#include"BSTree.h"
//平衡二叉排序樹的類型定義
#include"InsertAVL.c"
//功能模塊2-Status InsertAVL(BSTree *T,ElemType e,Status *taller);
//平衡二叉排序樹T插入元素e,taller為長高標志供遞歸調用時檢查
typedef BSTree SElemType;//這個很重要,定義棧的元素類型為二叉樹結點指針BSTree
#include"SqStack.h"
//順序棧的存儲結構
#include"SqStack.c"
//棧的操作:供非遞歸先序遍歷用
#include"Traverse.c"
//功能模塊3-void PreOrderTraverse(BSTree T,Status (*Visit)(ElemType e));非遞歸先序遍歷二叉樹
//void InOrderTraverse(BSTree T,Status(*Visit)(ElemType e));中序遍歷二叉樹
//void PostOrderTraverse(BSTree T,Status(*Visit)(ElemType e));后序遍歷二叉樹
//Status PrintElement(ElemType e);輸出元素函數,供遍歷調用
main()
{//主函數
BSTree T=NULL ;
//注意T必須先置空,非常重要
int i,ran[100];
//i為計數器,ran數組用于存放從RandomHundred函數隨機得來的1-100
Status taller ;
//長高與否標志,可以不初始化
printf("數據結構課程設計題目:\n");
printf("1--利用隨機函數產生100個(不大于100且各不相同的)隨機整數\n");
printf("2--用這些整數來生成一棵二叉樹\n");
printf("3--分別對二叉樹進行先序遍歷,中序遍歷和后序遍歷輸出樹中結點元素序列\n");
printf("注意:先序遍歷輸出要求采用非遞歸來實現\n\n");
printf("產生100個(不大于100且各不相同的)隨機整數:\n");
RandomHundred(ran);
for(i=0;i<100;++i)printf(FORMAT,ran[i]);
printf("\n\n");
for(i=0;i<100;++i)InsertAVL(&T,ran[i],&taller);
printf("已經按以上順序把這些整數一個一個插入平衡二叉排序樹!\n\n");
printf("先序遍歷二叉樹(采用非遞歸算法):\n");
PreOrderTraverse(T,PrintElement);
printf("\n");
printf("中序遍歷二叉樹:\n");
InOrderTraverse(T,PrintElement);
printf("\n");
printf("后序遍歷二叉樹:\n");
PostOrderTraverse(T,PrintElement);
printf("\n\n");
printf("課程設計題目演示完畢!\n06級統計一班 高翕山 200630980108\n");
getch();
}
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -