實驗三 二叉樹基本操作的實現
l 實驗目的
1、二叉樹的基本操作
(1)掌握二叉樹鏈表的結構和二叉排序樹的建立過程。
(2)掌握二叉樹排序樹的插入和刪除操作。
(3)加深對二叉樹的理解,逐步培養解決實際問題的編程能力。
2、樹的遍歷和哈夫曼樹
(1)掌握用遞歸方法實現二叉樹遍歷的操作。
(2)掌握用非遞歸方法實現二叉樹遍歷的操作。
(3)掌握建立Huffman樹的操作。
(4)加深對二叉樹的理解,逐步培養解決實際問題的編程能力。
l 實驗內容
1、二叉樹的基本操作
(一)基礎題
(1)SearchNode(TREE *tree,int key,TREE **pkpt,TREE **kpt)查找結點函數;
(2)InsertNode(TREE **tree,int key)二叉排序樹插入函數;
(3)DeleteNode(TREE **tree,int key)二叉排序樹刪除函數;
2.調用上述函數實現下列操作:
(1)初始化一棵二叉樹;
(2)調用插入函數建立一棵二叉排序樹;
(3)調用查找函數在二叉樹中查找指定的結點;
(二)提高題
【問題描述】已知以二叉樹鏈表作為存儲結構,試編寫按中序遍歷並打印二叉樹的算法。
【程序設計思路】采用一個棧,先將二叉樹的根結點入棧,若它有左子樹,便將左子樹的根節點入棧,直到左子樹為空,然后依次退棧並輸出結點值;若輸出的結點有右子樹,便將右子樹的根結點入棧,如此循環入棧、退棧,直到棧為空為止。
2、樹的遍歷和哈夫曼樹
(1)re_preorder(TREE *tree) 先序遍歷,采用遞歸方法;
(2)re_midorder(TREE *tree)中序遍歷,采用遞歸方法;
(3)re_posorder(TREE *tree) 后序遍歷,采用遞歸方法;
(4)st_preorder(TREE *tree)先序遍歷,采用鏈接棧的迭代方法;
(5)st_midorder(TREE *tree)中序遍歷,采用鏈接棧的迭代方法;
(6)st_posorder(TREE *tree)后序遍歷,采用鏈接棧的迭代方法;
2.調用上述函數實現下列操作:
(1)用遞歸方法分別實現先序、中序和后序遍歷二叉樹;
(2)用非遞歸方法分別實現先序、中序和后序遍歷二叉樹。
(3)程序源代碼

#include<stdio.h> #include<malloc.h> #include<conio.h> #include <windows.h> #include<stdlib.h> typedef struct tree /* 定義樹的結構*/ { int data; /*假定樹的元素類型為int*/ struct tree *lchild; /*左孩子*/ struct tree *rchild; /*右孩子*/ }TREE; typedef struct stack /*定義鏈接棧結構*/ { TREE *t; /*棧結點元素為指向二叉樹結點的指針*/ int flag; /*后序遍歷時用到該標志*/ struct stack *link;/*棧結點鏈接指針*/ }STACK; void gotoxy(int x,int y) //x為列坐標,y為行坐標 { COORD pos={x,y}; //設定坐標 HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE); //函數句柄 SetConsoleCursorPosition(hOut,pos); } void push(STACK **top,TREE *tree)/*樹結點入棧*/ { STACK *p; /*工作指針*/ p=(STACK*)malloc(sizeof(STACK));/*申請棧結點*/ p->t=tree; /*根結點進棧*/ p->link=*top; /*新棧結點指向棧頂*/ *top=p; /*棧頂為新結點*/ } void pop(STACK **top,TREE **tree)/*出棧*/ { STACK *p; if(*top==NULL) *tree=NULL; else { *tree=(*top)->t; p=*top; *top=(*top)->link; free(p); } } void SearchNode(TREE *tree,int key,TREE **pkpt,TREE **kpt)/*查找樹的根結點*/ { *pkpt=NULL; *kpt=tree; while(*kpt!=NULL) { if((*kpt)->data==key) return; *pkpt=*kpt; if(key<(*kpt)->data) *kpt=(*kpt)->lchild; else *kpt=(*kpt)->rchild; } } int InsertNode(TREE **tree,int key) /*在查找樹上插入新結點,返回1表示該鍵值結點已存在,返回-1表示內存申請失敗*/ { TREE *p,*q,*r; SearchNode(*tree,key,&p,&q); if(q!=NULL) return 1; if((r=(TREE*)malloc(sizeof(TREE)))==NULL) return -1; r->data=key; r->lchild=r->rchild=NULL; if(p==NULL) *tree=r; else if(p->data>key) p->lchild=r; else p->rchild=r; return 0; } int DeleteNode(TREE **tree,int key) /*在查找樹上刪除結點,返回1表示該鍵值結點不存在*/ { TREE *p,*q,*r; SearchNode(*tree,key,&p,&q); if(q==NULL) return 1; if(p==NULL) if(q->lchild==NULL) *tree=q->rchild; else { *tree=q->lchild; r=q->lchild; while(r->rchild!=NULL) r=r->rchild; r->rchild=q->rchild; } else if(q->lchild==NULL) if(q==p->lchild) p->lchild=q->rchild; else p->rchild=q->rchild; else { r=q->lchild; while(r->rchild!=NULL) r=r->rchild; r->rchild=q->rchild; if(q==p->lchild) p->lchild=q->lchild; else p->rchild=q->lchild; } free(q); return 0; } void OutputTree(TREE *tree) /*層次打印樹結點,中序遍歷,采用鏈接棧的迭代方法*/ { STACK *top; int deep=0,no=0,maxdeep=0; top=NULL; while(tree!=NULL||top!=NULL) { while(tree!=NULL) { push(&top,tree); top->flag=++deep; if(maxdeep<deep) maxdeep=deep; tree=tree->lchild; } if(top!=NULL) { deep=top->flag; no++; pop(&top,&tree); gotoxy(no *4,deep+2); printf("%d",tree->data); fflush(stdout); tree=tree->rchild; } } gotoxy(1,maxdeep+3); printf("任意鍵繼續\n"); getch(); } int main() { TREE *t; int op=-1,i,ret; t=NULL; while(op!=0) { printf("請選擇操作:\n-1-:增加樹結點\n-2-:刪除樹結點\n-0-:結束操作\n"); fflush(stdin); scanf("%d",&op); switch(op) { case 0: break; case 1: printf("請輸入樹結點元素:"); scanf("%d",&i); switch(InsertNode(&t,i)) { case 0: system("cls"); gotoxy(1,1); printf("成功,樹結構為:\n"); OutputTree(t); break; case 1: printf("該元素已存在"); break; default: printf("內存操作失敗"); break; } break; case 2: printf("請輸入要刪除的樹結點元素:"); scanf("%d",&i); if(DeleteNode(&t,i)){ system("cls"); gotoxy(1,1); printf("刪除成功,樹結構為:\n"); OutputTree(t); } else printf("該鍵植樹結點不存在\n"); break; } } }
(二)提高題
(1)程序源代碼:

#include<stdio.h> #include<malloc.h> #include<conio.h> #include <windows.h> #include<stdlib.h> typedef struct tree { int data; struct tree *lchild; struct tree *rchild; }TREE; typedef struct stack { TREE *t; int flag; struct stack *link; }STACK; void gotoxy(int x,int y) //x為列坐標,y為行坐標 { COORD pos={x,y}; //設定坐標 HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE); //函數句柄 SetConsoleCursorPosition(hOut,pos); } void push(STACK **top,TREE *tree) { STACK *p; p=(STACK*)malloc(sizeof(STACK)); p->t=tree; p->link=*top; *top=p; } void pop(STACK **top,TREE **tree) { STACK *p; if(*top==NULL) *tree=NULL; else { *tree=(*top)->t; p=*top; *top=(*top)->link; free(p); } } void OutputTree(TREE *tree) { STACK *top; int deep=0,no=0,maxdeep=0; top=NULL; while(tree!=NULL||top!=NULL) { while(tree!=NULL) { push(&top,tree); top->flag=++deep; if(maxdeep<deep) maxdeep=deep; tree=tree->lchild; } if(top!=NULL) { deep=top->flag; no++; pop(&top,&tree); gotoxy(no *4,deep+2); printf("%d",tree->data); fflush(stdout); tree=tree->rchild; } } gotoxy(1,maxdeep+3); printf("任意鍵繼續\n"); getch(); } 2、樹的遍歷和哈夫曼樹 (1)畫出數據結構基本運算的流程圖 (2)程序運行主要結果截圖 (3)程序源代碼 #include<stdio.h> #include<malloc.h> #include<conio.h> #include <windows.h> #include<stdlib.h> typedef struct tree /*定義樹結構*/ { int data; struct tree *lchild; struct tree *rchild; }TREE; typedef struct stack /*定義鏈接棧結構*/ { TREE *t; int flag; struct stack *link; }STACK; void re_preorder(TREE *tree) /*先序遍歷,采用遞歸方法*/ { if(tree!=NULL) { printf("%d",tree->data); re_preorder(tree->lchild); re_preorder(tree->rchild); } } void re_midorder(TREE *tree) /*中序遍歷,采用遞歸方法*/ { if(tree!=NULL) { re_midorder(tree->lchild); printf("%d",tree->data); re_midorder(tree->rchild); } } void re_posorder(TREE *tree) /*后序遍歷,采用遞歸方法*/ { if(tree!=NULL) { re_posorder(tree->lchild); re_posorder(tree->rchild); printf("%d",tree->data); } } void push(STACK **top,TREE *tree)/*樹結點入棧*/ { STACK *p; p=(STACK*)malloc(sizeof(STACK)); p->t=tree; p->link=*top; *top=p; } void pop(STACK **top,TREE **tree)/*出棧,棧內元素賦值給樹結點*/ { STACK *p; if(*top==NULL) *tree=NULL; else { *tree=(*top)->t; p=*top; *top=(*top)->link; free(p); } } void st_preorder(TREE *tree)/*先序遍歷,采用鏈接棧的迭代方法*/ { STACK *top; top=NULL; while(tree!=NULL) { printf("%d",tree->data); if(tree->rchild!=NULL) push(&top,tree->rchild); if(tree->lchild!=NULL) push(&top,tree->lchild); push(&top,tree->lchild); pop(&top,&tree); } } void st_midorder(TREE *tree)/*中序遍歷,采用鏈接棧的迭代方法*/ { STACK *top; top=NULL; while(tree!=NULL||top!=NULL) { while(tree!=NULL) { push(&top,tree); tree=tree->lchild; } if(top!=NULL) { pop(&top,&tree); printf("%d",tree->data); tree=tree->rchild; } } } void st_posorder(TREE *tree)/*后序遍歷,采用鏈接棧的迭代方法*/ { STACK *top; top=NULL; do{ while(tree!=NULL){ push(&top,tree); top->flag=0; tree=tree->lchild; } if(top!=NULL) { while(top!=NULL&&top->flag==1){ pop(&top,&tree); printf("%d",tree->data); } if(top!=NULL) { top->flag=1; tree=(top->t)->rchild; } } }while(top!=NULL); } void SearchNode(TREE *tree,int key,TREE **pkpt,TREE **kpt)/*查找樹根結點*/ { *pkpt=NULL; *kpt=tree; while(*kpt!=NULL) { if((*kpt)->data==key) return; *pkpt=*kpt; if(key<(*kpt)->data) *kpt=(*kpt)->lchild; else *kpt=(*kpt)->rchild; } } int InsertNode(TREE **tree,int key)/*在查找樹上插入新結點*/ { TREE *p,*q,*r; SearchNode(*tree,key,&p,&q); if(q!=NULL) return 1; if((r=(TREE*)malloc(sizeof(TREE)))==NULL) return -1; r->data=key; r->lchild=r->rchild=NULL; if(p==NULL) *tree=r; else if(p->data>key) p->lchild=r; else p->rchild=r; return 0; } void gotoxy(int x,int y) //x為列坐標,y為行坐標 { COORD pos={x,y}; //設定坐標 HANDLE hOut=GetStdHandle(STD_OUTPUT_HANDLE); //函數句柄 SetConsoleCursorPosition(hOut,pos); } void OutPutTree(TREE *tree)/*層次打印樹結點,*/ { STACK *top; int deep=0,no=0,maxdeep=0; top=NULL; while(tree!=NULL||top!=NULL) { while(tree!=NULL) { push(&top,tree); top->flag=++deep; if(maxdeep<deep) maxdeep=deep; tree=tree->lchild; } if(top!=NULL) { deep=top->flag; no++; pop(&top,&tree); gotoxy(no *4,deep+2); printf("%d",tree->data); fflush(stdout); tree=tree->rchild; } } gotoxy(1,maxdeep+3); printf("任意鍵繼續\n"); getch(); } int main() { TREE *t; int i,op=-1; t=NULL; while(op!=0) { printf("請選擇操作:\n-1-:增加數結點;\n-0-:結束操作\n"); fflush(stdin); scanf("%d",&op); switch(op) { case 0: break; case 1: printf("請輸入樹結點元素:"); scanf("%d",&i); switch(InsertNode(&t,i)) { case 0: system("cls"); gotoxy(1,1); printf("成功,數據結構為:\n"); OutPutTree(t); break; case 1: printf("該元素已存在"); break; default: printf("內存操作失敗"); break; } break; } } printf("先序遍歷,遞歸方法\n"); re_preorder(t); printf("\n任意鍵繼續\n\n"); getch(); printf("中序遍歷,遞歸方法\n"); re_midorder(t); printf("\n任意鍵繼續\n\n"); getch(); printf("后序遍歷,遞歸方法\n"); re_posorder(t); printf("\n任意鍵繼續\n\n"); getch(); printf("先序遍歷,采用鏈接棧的迭代方法\n"); st_preorder(t); printf("\n任意鍵繼續\n\n"); getch(); printf("中序遍歷,采用鏈接棧的迭代方法\n"); st_midorder(t); printf("\n任意鍵繼續\n\n"); getch(); printf("后序遍歷,采用鏈接棧的迭代方法\n"); st_posorder(t); printf("\n任意鍵繼續\n\n"); getch(); }
l 小結