C语言数据结构(大话数据结构——笔记4)第六章:树
文章目錄
- 第六章:樹(tree、root、subtree)(177)
- 樹的定義(179)
- 結點分類(結點的度degree、葉結點leaf[終端結點]、分支結點[非終端節點]{內部結點}、樹的度)(180)
- 結點間關系(結點的孩子child、孩子的雙親parent、結點的兄弟sibling、結點的祖先、結點的子孫)(180)
- 結點的層次level 樹的深度{高度}depth 有序樹、無序樹 森林forest(181)
- 樹結構與線性結構對比(182)
- 樹的抽象數據類型(182)
- 樹的存儲結構(183)
- 雙親表示法(183)
- 孩子表示法(186)
- 雙親孩子表示法(引出二叉樹概念)(189)
- 孩子兄弟表示法(190)
- 二叉樹(191)
- 二叉樹特點(五種基本形態)(193)
- 特殊二叉樹(斜樹、滿二叉樹、)(194)
- 斜樹(線性表一種特殊結構的表示)(194)
- 滿二叉樹(195)
- 完全二叉樹(195)
- 二叉樹的性質(197)
- 二叉樹的順序存儲結構(200)
- 完全二叉樹的存儲
- 一般二叉樹的存儲
- 右斜樹二叉樹的存儲
- 二叉樹的鏈式存儲(二叉鏈表)(201)
- 遍歷二叉樹(202)
- 前序遍歷(203)
- 中序遍歷
- 后序遍歷
- 層序遍歷(205)
- 遍歷算法(206)
- 前序遍歷算法(206)
- 中序遍歷算法(209)
- 后序遍歷算法(212)
- 遍歷推導結果(得出能夠唯一確定二叉樹的性質)(214)
- 二叉樹的建立(215)
- 原二叉樹的擴展二叉樹(215)
- 二叉樹新建結點(前序)遍歷結點代碼
- 線索二叉樹(216)
- 線索二叉樹的實現(219)
- 創建
- 遍歷
- 線索二叉樹的好處:可以像雙向鏈表那樣操作(221)
- 線索二叉樹完整實現代碼
- 樹、森林與二叉樹的轉換(223)
- 樹轉換成二叉樹(224)
- 森林轉換成二叉樹(225)
- 二叉樹轉化為樹(225)
- 二叉樹轉換為森林(226)
- 樹與森林的遍歷(結論:森林的前序遍歷和二叉樹的前序遍歷結果相同,森林的后序遍歷和二叉樹的中序遍歷結果相同)(227)
- 赫夫曼樹(最優二叉樹)及其應用(228)
- 赫夫曼樹(赫夫曼編碼)(228)
- 赫夫曼樹的定義與原理(231)
- 路徑長度
- 帶權路徑長度
- 赫夫曼樹構建步驟(232)
- 赫夫曼編碼(233)
- 前綴編碼(235)
- 構造霍夫曼編碼的方法(235)
- 第六章配套源碼
- 01二叉樹順序結構實現_BiTreeArray.cpp
- 02二叉樹鏈式結構實現_BiTreeLink.cpp
- 03線索二叉樹_ThreadBinaryTree.cpp
第六章:樹(tree、root、subtree)(177)
樹的定義(179)
結點分類(結點的度degree、葉結點leaf[終端結點]、分支結點[非終端節點]{內部結點}、樹的度)(180)
結點間關系(結點的孩子child、孩子的雙親parent、結點的兄弟sibling、結點的祖先、結點的子孫)(180)
結點的層次level 樹的深度{高度}depth 有序樹、無序樹 森林forest(181)
樹結構與線性結構對比(182)
樹的抽象數據類型(182)
樹的存儲結構(183)
雙親表示法(183)
改良,增加長子域,但這樣對于孩子大于兩個,就不知道如何表示了(185)
更關注兄弟,增加右兄弟域(185)
孩子表示法(186)
羅里吧嗦的,抓重點看!
雙親孩子表示法(引出二叉樹概念)(189)
但是這種方法不能知道結點的雙親是誰,可以改良一下:
這種結構叫做“雙親孩子表示法”!
孩子兄弟表示法(190)
把上面這圖變形(引出二叉樹概念):
二叉樹(191)
二叉樹特點(五種基本形態)(193)
五種基本形態:
1、空二叉樹
2、只有一個根結點
3、根結點只有左子樹
4、根結點只有右子樹
5、根結點既有左子樹又有右子樹
特殊二叉樹(斜樹、滿二叉樹、)(194)
斜樹(線性表一種特殊結構的表示)(194)
滿二叉樹(195)
完全二叉樹(195)
它的編號順序都是從上到下,從左到右的,不能“空擋”,否則就不是完全二叉樹了
二叉樹的性質(197)
二叉樹的順序存儲結構(200)
完全二叉樹的存儲
一般二叉樹的存儲
右斜樹二叉樹的存儲
右斜樹浪費空間,所以順序存儲結構一般只用于完全二叉樹
二叉樹的鏈式存儲(二叉鏈表)(201)
遍歷二叉樹(202)
前序遍歷(203)
用棧保存中間結點?
中序遍歷
后序遍歷
層序遍歷(205)
遍歷算法(206)
前序遍歷算法(206)
遞歸算法
遍歷結果:ABDHKECFIGJ
中序遍歷算法(209)
就是在前序遍歷算法順序上調了個個
遍歷結果:HKDBEAIFCGJ
后序遍歷算法(212)
遍歷結果:KHDEBIFJGCA
遍歷推導結果(得出能夠唯一確定二叉樹的性質)(214)
二叉樹的建立(215)
原二叉樹的擴展二叉樹(215)
二叉樹新建結點(前序)遍歷結點代碼
ps. 作者建立結構體的時候非得搞個什么附加命令,讓人摸不著頭腦,直接用二重指針表示它不香嗎?
#include <stdio.h> #include <stdlib.h> #include <cstdlib>//二叉鏈表結點 struct BiTNode {char data;BiTNode* lchild; BiTNode* rchild; };//新增結點 void CreateBiNode(BiTNode** A) {char ch;printf("請輸入結點字符:\n");scanf_s("%c", &ch, sizeof(ch));getchar();if (ch == '#')*A = NULL;else{*A = (BiTNode*)malloc(sizeof(BiTNode));if (!(*A))exit(OVERFLOW);(*A)->data = ch;CreateBiNode(&((*A)->lchild));CreateBiNode(&((*A)->rchild));}}//前序遍歷結點 void PreOrderTraverse(BiTNode* N) {if (NULL == N) {return;}printf("%c ", N->data);PreOrderTraverse(N->lchild);PreOrderTraverse(N->rchild);printf("\n"); }int main() {BiTNode* N;//要把指向結點的指針的指針傳進去才行,如果只是把指向結點的指針傳進去是沒有意義的,因為那個結點沒初始化CreateBiNode(&N);PreOrderTraverse(N); }運行結果:
請輸入結點字符: a 請輸入結點字符: b 請輸入結點字符: c 請輸入結點字符: e 請輸入結點字符: d 請輸入結點字符: # 請輸入結點字符: # 請輸入結點字符: # 請輸入結點字符: # 請輸入結點字符: # 請輸入結點字符: # a b c e d線索二叉樹(216)
指針域的空指針白白浪費空間
考慮在這些空指針的空間中存放指向前驅和后繼的指針(217)
線索二叉樹通過增加布爾變量標志位(存儲量比指針地址小),來展示這是子孩還是前驅 | 后繼
線索二叉樹的實現(219)
創建
遍歷
線索二叉樹的好處:可以像雙向鏈表那樣操作(221)
到A怎么到F?:A右標志位為0,直接就跳到C了
線索二叉樹完整實現代碼
#include "string.h" #include "stdio.h" #include "stdlib.h" #include "io.h" #include "math.h" #include "time.h"#define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0#define MAXSIZE 100 /* 存儲空間初始分配量 */typedef int Status; /* Status是函數的類型,其值是函數結果狀態代碼,如OK等 */ typedef char TElemType; typedef enum { Link, Thread } PointerTag; /* Link==0表示指向左右孩子指針, *//* Thread==1表示指向前驅或后繼的線索 */ typedef struct BiThrNode /* 二叉線索存儲結點結構 */ {TElemType data; /* 結點數據 */struct BiThrNode* lchild, * rchild; /* 左右孩子指針 */PointerTag LTag;PointerTag RTag; /* 左右標志 */ } BiThrNode, * BiThrTree;TElemType Nil = '#'; /* 字符型以空格符為空 */Status visit(TElemType e) {printf("%c ", e);return OK; }/* 按前序輸入二叉線索樹中結點的值,構造二叉線索樹T */ /* 0(整型)/空格(字符型)表示空結點 */ Status CreateBiThrTree(BiThrTree* T) {TElemType h;scanf_s("%c", &h, sizeof(h));if (h == Nil)*T = NULL;else{*T = (BiThrTree)malloc(sizeof(BiThrNode));if (!*T)exit(OVERFLOW);(*T)->data = h; /* 生成根結點(前序) */CreateBiThrTree(&(*T)->lchild); /* 遞歸構造左子樹 */if ((*T)->lchild) /* 有左孩子 */(*T)->LTag = Link;CreateBiThrTree(&(*T)->rchild); /* 遞歸構造右子樹 */if ((*T)->rchild) /* 有右孩子 */(*T)->RTag = Link;}return OK; }BiThrTree pre; /* 全局變量,始終指向剛剛訪問過的結點 */ /* 中序遍歷進行中序線索化 */ 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; /* 前驅右孩子指針指向后繼(當前結點p) */}pre = p; /* 保持pre指向p的前驅 */InThreading(p->rchild); /* 遞歸右子樹線索化 */} }/* 中序遍歷二叉樹T,并將其中序線索化,Thrt指向頭結點 */ Status InOrderThreading(BiThrTree* Thrt, BiThrTree T) {*Thrt = (BiThrTree)malloc(sizeof(BiThrNode));if (!*Thrt)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; }/* 中序遍歷二叉線索樹T(頭結點)的非遞歸算法 */ Status InOrderTraverse_Thr(BiThrTree T) {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;}return OK; }int main() {BiThrTree H, T;printf("請按前序輸入二叉樹(如:'ABDH##I##EJ###CF##G##')\n");CreateBiThrTree(&T); /* 按前序產生二叉樹 */InOrderThreading(&H, T); /* 中序遍歷,并中序線索化二叉樹 */printf("中序遍歷(輸出)二叉線索樹:\n");InOrderTraverse_Thr(H); /* 中序遍歷(輸出)二叉線索樹 */printf("\n");return 0; }運行結果:
請按前序輸入二叉樹(如:'ABDH##I##EJ###CF##G##') ABDH##I##EJ###CF##G## 中序遍歷(輸出)二叉線索樹: H D I B J E A F C GD:\Dontla_small_project\20210525_address_list\cc++list\dynamic_address_list\Debug\dynamic_address_list.exe (進程 31536) 已退出,代碼為 0。 按任意鍵關閉此窗口. . .樹、森林與二叉樹的轉換(223)
樹轉換成二叉樹(224)
森林轉換成二叉樹(225)
二叉樹轉化為樹(225)
二叉樹轉換為森林(226)
樹與森林的遍歷(結論:森林的前序遍歷和二叉樹的前序遍歷結果相同,森林的后序遍歷和二叉樹的中序遍歷結果相同)(227)
赫夫曼樹(最優二叉樹)及其應用(228)
赫夫曼樹(赫夫曼編碼)(228)
略
赫夫曼樹的定義與原理(231)
路徑長度
帶權路徑長度
赫夫曼樹構建步驟(232)
權值小的在左邊
赫夫曼編碼(233)
根據文本中字符出現的頻次不同,可以將字符重新編碼:
(原編碼)
(赫夫曼編碼)
但是這種長短不一的編碼該怎么解碼呢?
前綴編碼(235)
啥意思,看不懂。。。。
反正就是按照它約定的規則去解碼,只能存在一種情況,沒有多種情況啦!
構造霍夫曼編碼的方法(235)
第六章配套源碼
01二叉樹順序結構實現_BiTreeArray.cpp
#include "stdio.h" #include "stdlib.h" #include "io.h" #include "math.h" #include "time.h"#define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0#define MAXSIZE 100 /* 存儲空間初始分配量 */ #define MAX_TREE_SIZE 100 /* 二叉樹的最大結點數 */typedef int Status; /* Status是函數的類型,其值是函數結果狀態代碼,如OK等 */ typedef int TElemType; /* 樹結點的數據類型,目前暫定為整型 */ typedef TElemType SqBiTree[MAX_TREE_SIZE]; /* 0號單元存儲根結點 */typedef struct {int level, order; /* 結點的層,本層序號(按滿二叉樹計算) */ }Position;TElemType Nil = 0; /* 設整型以0為空 */Status visit(TElemType c) {printf("%d ", c);return OK; }/* 構造空二叉樹T。因為T是固定數組,不會改變,故不需要& */ Status InitBiTree(SqBiTree T) {int i;for (i = 0; i < MAX_TREE_SIZE; i++)T[i] = Nil; /* 初值為空 */return OK; }/* 按層序次序輸入二叉樹中結點的值(字符型或整型), 構造順序存儲的二叉樹T */ Status CreateBiTree(SqBiTree T) {int i = 0;printf("請按層序輸入結點的值(整型),0表示空結點,輸999結束。結點數≤%d:\n", MAX_TREE_SIZE);while (i < 10){T[i] = i + 1;if (i != 0 && T[(i + 1) / 2 - 1] == Nil && T[i] != Nil) /* 此結點(不空)無雙親且不是根 */{printf("出現無雙親的非根結點%d\n", T[i]);exit(ERROR);}i++;}while (i < MAX_TREE_SIZE){T[i] = Nil; /* 將空賦值給T的后面的結點 */i++;}return OK; }#define ClearBiTree InitBiTree /* 在順序存儲結構中,兩函數完全一樣 *//* 初始條件: 二叉樹T存在 */ /* 操作結果: 若T為空二叉樹,則返回TRUE,否則FALSE */ Status BiTreeEmpty(SqBiTree T) {if (T[0] == Nil) /* 根結點為空,則樹空 */return TRUE;elsereturn FALSE; }/* 初始條件: 二叉樹T存在。操作結果: 返回T的深度 */ int BiTreeDepth(SqBiTree T) {int i, j = -1;for (i = MAX_TREE_SIZE - 1; i >= 0; i--) /* 找到最后一個結點 */if (T[i] != Nil)break;i++;doj++;while (i >= powl(2, j));/* 計算2的j次冪。 */return j; }/* 初始條件: 二叉樹T存在 */ /* 操作結果: 當T不空,用e返回T的根,返回OK;否則返回ERROR,e無定義 */ Status Root(SqBiTree T, TElemType* e) {if (BiTreeEmpty(T)) /* T空 */return ERROR;else{*e = T[0];return OK;} }/* 初始條件: 二叉樹T存在,e是T中某個結點(的位置) */ /* 操作結果: 返回處于位置e(層,本層序號)的結點的值 */ TElemType Value(SqBiTree T, Position e) {return T[(int)powl(2, e.level - 1) + e.order - 2]; }/* 初始條件: 二叉樹T存在,e是T中某個結點(的位置) */ /* 操作結果: 給處于位置e(層,本層序號)的結點賦新值value */ Status Assign(SqBiTree T, Position e, TElemType value) {int i = (int)powl(2, e.level - 1) + e.order - 2; /* 將層、本層序號轉為矩陣的序號 */if (value != Nil && T[(i + 1) / 2 - 1] == Nil) /* 給葉子賦非空值但雙親為空 */return ERROR;else if (value == Nil && (T[i * 2 + 1] != Nil || T[i * 2 + 2] != Nil)) /* 給雙親賦空值但有葉子(不空) */return ERROR;T[i] = value;return OK; }/* 初始條件: 二叉樹T存在,e是T中某個結點 */ /* 操作結果: 若e是T的非根結點,則返回它的雙親,否則返回"空" */ TElemType Parent(SqBiTree T, TElemType e) {int i;if (T[0] == Nil) /* 空樹 */return Nil;for (i = 1; i <= MAX_TREE_SIZE - 1; i++)if (T[i] == e) /* 找到e */return T[(i + 1) / 2 - 1];return Nil; /* 沒找到e */ }/* 初始條件: 二叉樹T存在,e是T中某個結點 */ /* 操作結果: 返回e的左孩子。若e無左孩子,則返回"空" */ TElemType LeftChild(SqBiTree T, TElemType e) {int i;if (T[0] == Nil) /* 空樹 */return Nil;for (i = 0; i <= MAX_TREE_SIZE - 1; i++)if (T[i] == e) /* 找到e */return T[i * 2 + 1];return Nil; /* 沒找到e */ }/* 初始條件: 二叉樹T存在,e是T中某個結點 */ /* 操作結果: 返回e的右孩子。若e無右孩子,則返回"空" */ TElemType RightChild(SqBiTree T, TElemType e) {int i;if (T[0] == Nil) /* 空樹 */return Nil;for (i = 0; i <= MAX_TREE_SIZE - 1; i++)if (T[i] == e) /* 找到e */return T[i * 2 + 2];return Nil; /* 沒找到e */ }/* 初始條件: 二叉樹T存在,e是T中某個結點 */ /* 操作結果: 返回e的左兄弟。若e是T的左孩子或無左兄弟,則返回"空" */ TElemType LeftSibling(SqBiTree T, TElemType e) {int i;if (T[0] == Nil) /* 空樹 */return Nil;for (i = 1; i <= MAX_TREE_SIZE - 1; i++)if (T[i] == e && i % 2 == 0) /* 找到e且其序號為偶數(是右孩子) */return T[i - 1];return Nil; /* 沒找到e */ }/* 初始條件: 二叉樹T存在,e是T中某個結點 */ /* 操作結果: 返回e的右兄弟。若e是T的右孩子或無右兄弟,則返回"空" */ TElemType RightSibling(SqBiTree T, TElemType e) {int i;if (T[0] == Nil) /* 空樹 */return Nil;for (i = 1; i <= MAX_TREE_SIZE - 1; i++)if (T[i] == e && i % 2) /* 找到e且其序號為奇數(是左孩子) */return T[i + 1];return Nil; /* 沒找到e */ }/* PreOrderTraverse()調用 */ void PreTraverse(SqBiTree T, int e) {visit(T[e]);if (T[2 * e + 1] != Nil) /* 左子樹不空 */PreTraverse(T, 2 * e + 1);if (T[2 * e + 2] != Nil) /* 右子樹不空 */PreTraverse(T, 2 * e + 2); }/* 初始條件: 二叉樹存在 */ /* 操作結果: 先序遍歷T。 */ Status PreOrderTraverse(SqBiTree T) {if (!BiTreeEmpty(T)) /* 樹不空 */PreTraverse(T, 0);printf("\n");return OK; }/* InOrderTraverse()調用 */ void InTraverse(SqBiTree T, int e) {if (T[2 * e + 1] != Nil) /* 左子樹不空 */InTraverse(T, 2 * e + 1);visit(T[e]);if (T[2 * e + 2] != Nil) /* 右子樹不空 */InTraverse(T, 2 * e + 2); }/* 初始條件: 二叉樹存在 */ /* 操作結果: 中序遍歷T。 */ Status InOrderTraverse(SqBiTree T) {if (!BiTreeEmpty(T)) /* 樹不空 */InTraverse(T, 0);printf("\n");return OK; }/* PostOrderTraverse()調用 */ void PostTraverse(SqBiTree T, int e) {if (T[2 * e + 1] != Nil) /* 左子樹不空 */PostTraverse(T, 2 * e + 1);if (T[2 * e + 2] != Nil) /* 右子樹不空 */PostTraverse(T, 2 * e + 2);visit(T[e]); }/* 初始條件: 二叉樹T存在 */ /* 操作結果: 后序遍歷T。 */ Status PostOrderTraverse(SqBiTree T) {if (!BiTreeEmpty(T)) /* 樹不空 */PostTraverse(T, 0);printf("\n");return OK; }/* 層序遍歷二叉樹 */ void LevelOrderTraverse(SqBiTree T) {int i = MAX_TREE_SIZE - 1, j;while (T[i] == Nil)i--; /* 找到最后一個非空結點的序號 */for (j = 0; j <= i; j++) /* 從根結點起,按層序遍歷二叉樹 */if (T[j] != Nil)visit(T[j]); /* 只遍歷非空的結點 */printf("\n"); }/* 逐層、按本層序號輸出二叉樹 */ void Print(SqBiTree T) {int j, k;Position p;TElemType e;for (j = 1; j <= BiTreeDepth(T); j++){printf("第%d層: ", j);for (k = 1; k <= powl(2, j - 1); k++){p.level = j;p.order = k;e = Value(T, p);if (e != Nil)printf("%d:%d ", k, e);}printf("\n");} }int main() {Status i;Position p;TElemType e;SqBiTree T;InitBiTree(T);CreateBiTree(T);printf("建立二叉樹后,樹空否?%d(1:是 0:否) 樹的深度=%d\n", BiTreeEmpty(T), BiTreeDepth(T));i = Root(T, &e);if (i)printf("二叉樹的根為:%d\n", e);elseprintf("樹空,無根\n");printf("層序遍歷二叉樹:\n");LevelOrderTraverse(T);printf("前序遍歷二叉樹:\n");PreOrderTraverse(T);printf("中序遍歷二叉樹:\n");InOrderTraverse(T);printf("后序遍歷二叉樹:\n");PostOrderTraverse(T);printf("修改結點的層號3本層序號2。");p.level = 3;p.order = 2;e = Value(T, p);printf("待修改結點的原值為%d請輸入新值:50 ", e);e = 50;Assign(T, p, e);printf("前序遍歷二叉樹:\n");PreOrderTraverse(T);printf("結點%d的雙親為%d,左右孩子分別為", e, Parent(T, e));printf("%d,%d,左右兄弟分別為", LeftChild(T, e), RightChild(T, e));printf("%d,%d\n", LeftSibling(T, e), RightSibling(T, e));ClearBiTree(T);printf("清除二叉樹后,樹空否?%d(1:是 0:否) 樹的深度=%d\n", BiTreeEmpty(T), BiTreeDepth(T));i = Root(T, &e);if (i)printf("二叉樹的根為:%d\n", e);elseprintf("樹空,無根\n");return 0; }運行結果:
請按層序輸入結點的值(整型),0表示空結點,輸999結束。結點數≤100: 建立二叉樹后,樹空否?0(1:是 0:否) 樹的深度=4 二叉樹的根為:1 層序遍歷二叉樹: 1 2 3 4 5 6 7 8 9 10 前序遍歷二叉樹: 1 2 4 8 9 5 10 3 6 7 中序遍歷二叉樹: 8 4 9 2 10 5 1 6 3 7 后序遍歷二叉樹: 8 9 4 10 5 2 6 7 3 1 修改結點的層號3本層序號2。待修改結點的原值為5請輸入新值:50 前序遍歷二叉樹: 1 2 4 8 9 50 10 3 6 7 結點50的雙親為2,左右孩子分別為10,0,左右兄弟分別為4,0 清除二叉樹后,樹空否?1(1:是 0:否) 樹的深度=0 樹空,無根02二叉樹鏈式結構實現_BiTreeLink.cpp
#include "string.h" #include "stdio.h" #include "stdlib.h" #include "io.h" #include "math.h" #include "time.h"#define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0#define MAXSIZE 100 /* 存儲空間初始分配量 */typedef int Status; /* Status是函數的類型,其值是函數結果狀態代碼,如OK等 *//* 用于構造二叉樹********************************** */ int index = 1; typedef char String[24]; /* 0號單元存放串的長度 */ String str;Status StrAssign(String T, const char* chars) {int i;if (strlen(chars) > MAXSIZE)return ERROR;else{T[0] = strlen(chars);for (i = 1; i <= T[0]; i++)T[i] = *(chars + i - 1);return OK;} } /* ************************************************ */typedef char TElemType; TElemType Nil = ' '; /* 字符型以空格符為空 */Status visit(TElemType e) {printf("%c ", e);return OK; }typedef struct BiTNode /* 結點結構 */ {TElemType data; /* 結點數據 */struct BiTNode* lchild, * rchild; /* 左右孩子指針 */ }BiTNode, * BiTree;/* 構造空二叉樹T */ Status InitBiTree(BiTree* T) {*T = NULL;return OK; }/* 初始條件: 二叉樹T存在。操作結果: 銷毀二叉樹T */ void DestroyBiTree(BiTree* T) {if (*T){if ((*T)->lchild) /* 有左孩子 */DestroyBiTree(&(*T)->lchild); /* 銷毀左孩子子樹 */if ((*T)->rchild) /* 有右孩子 */DestroyBiTree(&(*T)->rchild); /* 銷毀右孩子子樹 */free(*T); /* 釋放根結點 */*T = NULL; /* 空指針賦0 */} }/* 按前序輸入二叉樹中結點的值(一個字符) */ /* #表示空樹,構造二叉鏈表表示二叉樹T。 */ void CreateBiTree(BiTree* T) {TElemType ch;/* scanf("%c",&ch); */ch = str[index++];if (ch == '#')*T = NULL;else{*T = (BiTree)malloc(sizeof(BiTNode));if (!*T)exit(OVERFLOW);(*T)->data = ch; /* 生成根結點 */CreateBiTree(&(*T)->lchild); /* 構造左子樹 */CreateBiTree(&(*T)->rchild); /* 構造右子樹 */} }/* 初始條件: 二叉樹T存在 */ /* 操作結果: 若T為空二叉樹,則返回TRUE,否則FALSE */ Status BiTreeEmpty(BiTree T) {if (T)return FALSE;elsereturn TRUE; }#define ClearBiTree DestroyBiTree/* 初始條件: 二叉樹T存在。操作結果: 返回T的深度 */ int BiTreeDepth(BiTree T) {int i, j;if (!T)return 0;if (T->lchild)i = BiTreeDepth(T->lchild);elsei = 0;if (T->rchild)j = BiTreeDepth(T->rchild);elsej = 0;return i > j ? i + 1 : j + 1; }/* 初始條件: 二叉樹T存在。操作結果: 返回T的根 */ TElemType Root(BiTree T) {if (BiTreeEmpty(T))return Nil;elsereturn T->data; }/* 初始條件: 二叉樹T存在,p指向T中某個結點 */ /* 操作結果: 返回p所指結點的值 */ TElemType Value(BiTree p) {return p->data; }/* 給p所指結點賦值為value */ void Assign(BiTree p, TElemType value) {p->data = value; }/* 初始條件: 二叉樹T存在 */ /* 操作結果: 前序遞歸遍歷T */ void PreOrderTraverse(BiTree T) {if (T == NULL)return;printf("%c", T->data);/* 顯示結點數據,可以更改為其它對結點操作 */PreOrderTraverse(T->lchild); /* 再先序遍歷左子樹 */PreOrderTraverse(T->rchild); /* 最后先序遍歷右子樹 */ }/* 初始條件: 二叉樹T存在 */ /* 操作結果: 中序遞歸遍歷T */ void InOrderTraverse(BiTree T) {if (T == NULL)return;InOrderTraverse(T->lchild); /* 中序遍歷左子樹 */printf("%c", T->data);/* 顯示結點數據,可以更改為其它對結點操作 */InOrderTraverse(T->rchild); /* 最后中序遍歷右子樹 */ }/* 初始條件: 二叉樹T存在 */ /* 操作結果: 后序遞歸遍歷T */ void PostOrderTraverse(BiTree T) {if (T == NULL)return;PostOrderTraverse(T->lchild); /* 先后序遍歷左子樹 */PostOrderTraverse(T->rchild); /* 再后序遍歷右子樹 */printf("%c", T->data);/* 顯示結點數據,可以更改為其它對結點操作 */ }int main() {int i;BiTree T;TElemType e1;InitBiTree(&T);StrAssign(str, "ABDH#K###E##CFI###G#J##");CreateBiTree(&T);printf("構造空二叉樹后,樹空否?%d(1:是 0:否) 樹的深度=%d\n", BiTreeEmpty(T), BiTreeDepth(T));e1 = Root(T);printf("二叉樹的根為: %c\n", e1);printf("\n前序遍歷二叉樹:");PreOrderTraverse(T);printf("\n中序遍歷二叉樹:");InOrderTraverse(T);printf("\n后序遍歷二叉樹:");PostOrderTraverse(T);ClearBiTree(&T);printf("\n清除二叉樹后,樹空否?%d(1:是 0:否) 樹的深度=%d\n", BiTreeEmpty(T), BiTreeDepth(T));i = Root(T);if (!i)printf("樹空,無根\n");return 0; }運行結果:
構造空二叉樹后,樹空否?0(1:是 0:否) 樹的深度=5 二叉樹的根為: A前序遍歷二叉樹:ABDHKECFIGJ 中序遍歷二叉樹:HKDBEAIFCGJ 后序遍歷二叉樹:KHDEBIFJGCA 清除二叉樹后,樹空否?1(1:是 0:否) 樹的深度=003線索二叉樹_ThreadBinaryTree.cpp
#include "string.h" #include "stdio.h" #include "stdlib.h" #include "io.h" #include "math.h" #include "time.h"#define OK 1 #define ERROR 0 #define TRUE 1 #define FALSE 0#define MAXSIZE 100 /* 存儲空間初始分配量 */typedef int Status; /* Status是函數的類型,其值是函數結果狀態代碼,如OK等 */ typedef char TElemType; typedef enum { Link, Thread } PointerTag; /* Link==0表示指向左右孩子指針, *//* Thread==1表示指向前驅或后繼的線索 */ typedef struct BiThrNode /* 二叉線索存儲結點結構 */ {TElemType data; /* 結點數據 */struct BiThrNode* lchild, * rchild; /* 左右孩子指針 */PointerTag LTag;PointerTag RTag; /* 左右標志 */ } BiThrNode, * BiThrTree;TElemType Nil = '#'; /* 字符型以空格符為空 */Status visit(TElemType e) {printf("%c ", e);return OK; }/* 按前序輸入二叉線索樹中結點的值,構造二叉線索樹T */ /* 0(整型)/空格(字符型)表示空結點 */ Status CreateBiThrTree(BiThrTree* T) {TElemType h;scanf_s("%c", &h, sizeof(h));if (h == Nil)*T = NULL;else{*T = (BiThrTree)malloc(sizeof(BiThrNode));if (!*T)exit(OVERFLOW);(*T)->data = h; /* 生成根結點(前序) */CreateBiThrTree(&(*T)->lchild); /* 遞歸構造左子樹 */if ((*T)->lchild) /* 有左孩子 */(*T)->LTag = Link;CreateBiThrTree(&(*T)->rchild); /* 遞歸構造右子樹 */if ((*T)->rchild) /* 有右孩子 */(*T)->RTag = Link;}return OK; }BiThrTree pre; /* 全局變量,始終指向剛剛訪問過的結點 */ /* 中序遍歷進行中序線索化 */ 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; /* 前驅右孩子指針指向后繼(當前結點p) */}pre = p; /* 保持pre指向p的前驅 */InThreading(p->rchild); /* 遞歸右子樹線索化 */} }/* 中序遍歷二叉樹T,并將其中序線索化,Thrt指向頭結點 */ Status InOrderThreading(BiThrTree* Thrt, BiThrTree T) {*Thrt = (BiThrTree)malloc(sizeof(BiThrNode));if (!*Thrt)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; }/* 中序遍歷二叉線索樹T(頭結點)的非遞歸算法 */ Status InOrderTraverse_Thr(BiThrTree T) {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;}return OK; }int main() {BiThrTree H, T;printf("請按前序輸入二叉樹(如:'ABDH##I##EJ###CF##G##')\n");CreateBiThrTree(&T); /* 按前序產生二叉樹 */InOrderThreading(&H, T); /* 中序遍歷,并中序線索化二叉樹 */printf("中序遍歷(輸出)二叉線索樹:\n");InOrderTraverse_Thr(H); /* 中序遍歷(輸出)二叉線索樹 */printf("\n");return 0; }運行結果:
請按前序輸入二叉樹(如:'ABDH##I##EJ###CF##G##') ABDH##I##EJ###CF##G## 中序遍歷(輸出)二叉線索樹: H D I B J E A F C G總結
以上是生活随笔為你收集整理的C语言数据结构(大话数据结构——笔记4)第六章:树的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C语言数据结构(大话数据结构——笔记3)
- 下一篇: C语言中函数如何返回结构体?