实验七 查找实验
7.1 实验目的
(1) 掌握顺序表的查找方法,尤其是二分查找方法。
(2) 掌握二叉排序树的建立及查找。
查找是软件设计中的最常用的运算,查找所涉及到的表结构的不同决定了查找的方法及其性能。二分查找是顺序表的查找中的最重要的方法,应能充分理解其实现方法和有关性能,并能借助其判定树结构来加深理解。二叉排序树结构在实验时具有一定的难度,可结合二叉树的有关内容和方法来实现。
7.2 实验要求
- 查找表的定义和算法实现放入库文件,如“search.h”中;
- 查找的测试数据用文本文件方式给出,例如测试数据名为ser.dat;
- 可多次连续测试。
7.3 实验任务
编写算法实现下列问题的求解。
- 对下列数据表,分别采用二分查找算法实现查找,给出查找过程依次所比较的元素(的下标),并以二分查找的判定树来解场释。
【算法思想】:
先构建函数来读取对应的文件,对文件中的数据进行读取。由于二分查找的判定树中序输出为从小到大顺序输出,所以使用二分法对树进行模拟。利用mid=low+high>>1来进行折半查找。通过low<=high来判断循环是否继续。最终函数返回int,如果返回是1,则查找成功,如果函数返回结果是0,则查找失败。
【算法描述】:
int bin_search(element a[], int n, keytype x) {//二分法
int mid, low = 0, high = n - 1;//下标
while (low <= high) {
mid = low + high >> 1;
cout << mid << " ";
if (x == a[mid])return mid;
else if (x < a[mid])high = mid - 1;
else {
low = mid + 1;
}
}
return 0;
}
第一组测试数据:
数据表为 (1,2,3,4,6,7,8,9,10,11,12,13,17,18,19,20,24,25,26,30,35,40,45,50,,100)
查找的元素分别为: 2,8,20, 30,50,5,15,33,110
第二组数据:
数据表为 (2,3,5,7,8,10,12,15,18,20,22,25,30,35,40,45,50,55,60, 80,100)
查找的元素分别为: 22,8,80,3,100,1,13,120
- 设计出在二叉排序树中插入结点的算法,在此基础上实现构建二叉排序树的算法。
【算法思想】:
先构建函数来读取对应的文件,对文件中的数据进行读取。通过二叉树结点进行构建。按照中序遍历为顺序的结构进行建树。如果所求的值偏大,去子树的右半部分进行查找,偏小则去子树的左半部分进行查找。在根指针T所指二叉排序树中递归地查找某关键字等于key的数据元素。若查找成功,则返回指向该数据元素结点的指针,否则返回空指针。最后输出查找的最终结果。
【算法描述】:
void lu_find_read(elementype x[]) {
FILE* pFile; //定义二叉树的文件指针
char fileName[MAXLEN];
cout << "请输入对应的数据文件名ser.txt" << endl;
//char str[1000]; //存放读出一行文本的字符串
//char strTemp[10]; //判断是否注释行
cin >> fileName;//输入文件名
int err = fopen_s(&pFile, fileName, "r");
if (err != 0)
return;
if (!pFile) {
cout << "错误:文件" << fileName << "打开失败。" << endl;
return;
}
/*while (fgets(str, 1000, pFile) != NULL) { //跳过空行和注释行
strLTrim(str); //删除字符串左边空格
if (str[0] == '\n') //空行,继续读取下一行
continue;
strncpy_s(strTemp, str, 2);
//strTemp[1] = 0;
if (strstr(strTemp, "//") != NULL) //跳过注释行
continue;
else //非注释行、非空行,跳出循环
break;
}*/
/*while () {
char c = fgetc(pFile)
if (c!=',') {
}
}
if(char c = fgetc(pFile); //读取一个字符)
char c = fgetc(pFile); //读取一个字符
*/
fgets(x, 0xFF, pFile); //读取一行字符串
fclose(pFile);//关闭文件
}
//卢氏建树
void build(Bnode** t,elementype c[]) {
string s = "";
for (int i = 0; i < strlen(c); i++) {
if (c[i] != ',') {
s = s + c[i];
}
else {
int len = s.size();
int all = 0;
for (int j = 0; j < len; j++) {
all *= 10;
all += s[j] - '0';
}
s = "";
Bnode* ss = new Bnode;
ss->data = all;
ss->lChild = NULL;
ss->rChild = NULL;
//Bnode*sss = &ss;
insert(t, ss);//塞结点
}
}
}
//中序遍历
void inorder(Bnode* root)
{
if (root == nullptr) {}
else {
if (root->lChild != nullptr)
inorder(root->lChild);
cout << root->data << ",";
if (root->rChild != nullptr)
inorder(root->rChild);
}
}
//查找
Bnode SearchBST(Bnode* T, int key) {
//在根指针T所指二叉排序树中递归地查找某关键字等于key的数据元素
//若查找成功,则返回指向该数据元素结点的指针,否则返回空指针
if ((!T) || key == T->data) {
if (!T) {
cout << "查找失败" << endl;
return *T;
}
if (key == T->data) {
cout << "查找成功" << endl;
return *T;
}
} //查找结束
else if (key < T->data) return SearchBST(T->lchild, key); //在左子树中继续查找
else return SearchBST(T->rchild, key); //在右子树中继续查找
} // SearchBST
测试数据:构建二叉排序树的输入序列如下:
第一组数据:
100,150,120,50,70,60,80,170,180,160,110,30,40,35,175
第二组数据:
100,70,60,80,150,120,50,160,30,40,170,180,175,35
(3) 设计算法在二叉排序树中查找指定值的结点。
测试数据:在任务(1)中第一组测试数据所构造的二叉排序树中,分别查找下列元素: 150,70,160,190,10,55,175
【算法思想】:
任务一中的二叉排序树主要以数组的形式进行模拟,任务二的二叉排序树主要以结点与指针的形式进行模拟。前者可通过顺序排序后进行二分查找的方法进行查找。后者主要通过构建二叉树的方式进行查找,本质上还是二分查找,此二叉树较为特殊,左子树全是小于根节点的,右子树全是大于根节点的。
【算法描述】:
//查找
Bnode SearchBST(Bnode* T, int key) {
//在根指针T所指二叉排序树中递归地查找某关键字等于key的数据元素
//若查找成功,则返回指向该数据元素结点的指针,否则返回空指针
if ((!T) || key == T->data) {
if (!T) {
cout << "查找失败" << endl;
return *T;
}
if (key == T->data) {
cout << "查找成功" << endl;
return *T;
}
} //查找结束
else if (key < T->data) return SearchBST(T->lchild, key); //在左子树中继续查找
else return SearchBST(T->rchild, key); //在右子树中继续查找
} // SearchBST
(4) 设计算法在二叉排序树中删除特定值的结点。
测试数据:在任务(1)中第一组测试数据所构造的二叉排序树中,分别删除下列元素:30,150,100
【算法思想】:
首先,为了删除目标节点,需要先找到该结点,通过递归调用找到该节点(如果根节点不等于目标值,若大于则去右子树上去找,若小于则去左子树上去找);找到要删除的结点后,如果即将被删除的节点有两个孩子,那么用右面的孩子来取代该节点,同时在该子树上找到最小节点元素,并将该节点元素删除。如果其只有一个孩子或者根本无孩子结点:用新建结点指针p指向当前目标结点,让BST向孩子方向移动(若无孩子结点则不移动),释放p所指的结点。
【算法描述】:
Bnode* Delete(Bnode* BST, int x)
{
Bnode* p;
if (BST == NULL) //如果树为空直接返回
return NULL;
else if (x < BST->data) //小于则左子树递归删除
BST->lChild = Delete(BST->lchild, x);
else if (x > BST->data) //大于则右子树递归删除
BST->rchild = Delete(BST->rchild, x);
else //等于则找到了要删除的结点
{
//如果被删除的结点有左、右两个孩子结点
if (BST->lchild && BST->rchild)
{
//找到右子树的最小元素
p = FindMin(BST->rchild);
//替代被删除的结点
BST->data = p->data;
//在被删除结点的右子树中删除刚才找到的右子树的最小元素
BST->rchild = Delete(BST->rchild, p->data);
}
//如果被删除结点只有一个孩子结点或没有孩子结点
else
{
p = BST;
if (BST->lchild == NULL) //有右孩子结点或没有孩子结点
BST = BST->rchild;
else if (BST->rchild == NULL) //有左孩子结点或没有孩子结点
BST = BST->lchild;
free(p); //释放结点
}
}
return BST;
}
注释:以下结果为一次性删除所有数据后的结果:
(5) 设计算法,对给定的二叉排序树,求出在等概论情况下的平均查找长度。
测试数据:构建二叉排序树的输入序列如下:
第一组数据:
100,150,120,50,70,60,80,170,180,160,110,30,40,35,175
第二组数据:
100,70,60,80,150,120,50,160,30,40,170,180,175,35
【算法思想】:
首先,如前面的任务一样,根据文件读写到的数据查找二叉排序树中的对应节点,在传入数据中,利用lu_all来记录查找的次数。利用递归方法来查找某关键字等于key的元素,查找成功则返回指向该元素结点的指针,否则返回空指针。利用for循环根据读写到的元素个数,分别进行一次查找,最后lu_all+=每次的查找次数,(double)(num / n)最终得出平均查找次数。
【算法描述】:
//查找+计数
Bnode *SearchBST2(Bnode* T, int key,int &lu_all) {
//在根指针T所指二叉排序树中递归地查找某关键字等于key的数据元素
//若查找成功,则返回指向该数据元素结点的指针,否则返回空指针
lu_all++;
if ((!T) || key == T->data) {
if (!T) {
cout << "查找失败" << endl;
return T;
}
if (key == T->data) {
cout << "查找成功" << endl;
return T;
}
} //查找结束
else if (key < T->data) return SearchBST2(T->lchild, key,lu_all); //在左子树中继续查找
else return SearchBST2(T->rchild, key,lu_all); //在右子树中继续查找
} // SearchBST
int chatt;
cout << "请输入您采用的数据(3 or 4)" << endl;
cin >> chatt;
if (chatt == 3) {
for (int i = 0; i <= 14; i++) {
int luall = 0;
int test1 = c[i];
SearchBST2(tt, test1,luall);
num += luall;
}
cout << "平均查找长度为:" << endl;
cout << (double)(num / 15 )<< endl;
}
else {
for (int i = 0; i <= 13; i++) {
int luall = 0;
int test1 = d[i];
SearchBST2(tt, test1, luall);
num += luall;
}
cout << "平均查找长度为:" << endl;
cout << (double)(num / 14) << endl;
}
(6) 对给定的二叉树,假设其中各结点的值均不相同,设计算法以判断该二叉树是否是二叉排序树。
【算法思想】:
此题我有两种实现方法,首先第一种通过输入的各个元素值,构建正确的二叉排序树,通过返回对应的二叉树根节点指针与题中所给的数据挨个元素经行对比,进行中序遍历,与题中数据对比后,若有数据不同则二叉排序树并非正确。
第二种,利用vector数组进行中序遍历,将读入的数据从二叉树转变为顺序输出的数组。利用递归遍历该二叉树结构,将对应的元素值储存到动态数组vector中。将读取到元素值与动态数组中储存的元素值进行对比,若一样则为线索二叉树,若不一样则不是。
【算法描述】:
bool Func(Bnode* T) {
if (T) {
if (NULL == T->lChild && NULL == T->rChild) {
return true;
}
else if (NULL == T->lChild) {
if (T->data < T->rChild->data) {
return Func(T->rChild);
}
else {
return false;
}
}
else if (NULL == T->rChild) {
if (T->data > T->lChild->data) {
return Func(T->lChild);
}
else {
return false;
}
}
else {
if (T->data < T->rChild->data && T->data > T->lChild->data) {
return (Func(T->rChild) && Func(T->lChild));
}
else {
return false;
}
}
}
}
vector<int> datas;
vector<int> preorderTraversal(btNode* root) {
if (root == nullptr) // 递归退出条件
return datas;
else
datas.push_back(root->data); // 递归遍历父节点,也是当前节点
preorderTraversal(root->lchild); // 递归遍历左子节点
preorderTraversal(root->rchild); // 递归遍历右子节点
return datas;
}
void QianXvBianLi(vector<int> datas) {
for (int i = 0; i < datas.size(); i++) {
cout << datas[i] << " ";
}
}
测试数据:构建二叉排序树的输入序列如下:
第一组数据:
100,150,120,50,70,60,80,170,180,160,110,30,40,35,175
第二组数据:
-
-
- 80,150,120,50,160,30,40,170,180,175,35
-
#include<iostream>
#include<string>
#include <stdio.h>
#include<vector>
#include <stdlib.h>
#include"search.h"
using namespace std;
int main() {
elementype x[MAXLEN];
Bnode* tt = new Bnode;
tt = NULL;
Bnode* pt = new Bnode;
int a[25] = { 1,2,3,4,6,7,8,9,10,11,12,13,17,18,19,20,24,25,26,30,35,40,45,50,100 };
int b[21] = { 2,3,5,7,8,10,12,15,18,20,22,25,30,35,40,45,50,55,60, 80,100 };
int c[15] = { 100,150,120,50,70,60,80,170,180,160,110,30,40,35,175 };
//100,150,120,50,70,60,80,170,180,160,110,30,40,35,175,
int d[14] = { 100,70,60,80,150,120,50,160,30,40,170,180,175,35 };
double num = 0.0;
int lu = 1;
do {
int nChoice;
//创建菜单
cout << "****** 二叉树二叉链表结构测试程序 ******" << endl;
cout << "* 0--退出 *" << endl;
cout << "* 1--文件创建二叉树 *" << endl;
cout << "* 2--给出查找过程二分查找 *" << endl;
cout << "* 3--在二叉排序树中查找指定值的结点 *" << endl;
cout << "* 4--删除特定值的结点 *" << endl;
cout << "* 5--等概论情况下的平均查找长度 *" << endl;
cout << "* 6--判断该二叉树是否是二叉排序树 *" << endl;
cout << "****************************************" << endl;
cout << "请选择操作:";
cin >> nChoice;
switch (nChoice) {
case 0: //退出程序
cout << "<-- 程序退出 -->" << endl; //选择退出
lu = 0;
break;
case 1:
lu_find_read(x);
build(&tt, x);
inorder(tt);
cout << endl;
break;
case 2:
int chat;
cout << "请输入您采用的数据(1 or 2)" << endl;
cin >> chat;
if(chat==1){
keytype val;
cout << "请输入您要查找的元素" << endl;
cin >> val;
cout << "查找经历为:" << endl;
if (!bin_search(a, 25, val)) {
cout << "查找失败!!!" << endl;
}
cout << endl;
}
else {
keytype val;
cout << "请输入您要查找的元素" << endl;
cin >> val;
cout << "查找经历为:" << endl;
if (!bin_search(b, 21, val)) {
cout << "查找失败!!!" << endl;
}
cout << endl;
}
break;
case 3:
int key;
cout << "请输入你要查找的值:" << endl;
cin >> key;
SearchBST(tt, key);
break;
case 4:
int keyy;
cout << "请输入你要删除的值:" << endl;
cin >> keyy;
Delete(tt, keyy);
cout << "删除后的结果:" << endl;
inorder(tt);
cout << endl;
break;
case 5:
int chatt;
cout << "请输入您采用的数据(3 or 4)" << endl;
cin >> chatt;
if (chatt == 3) {
for (int i = 0; i <= 14; i++) {
float luall = 0.0;
int test1 = c[i];
SearchBST2(tt, test1,luall);
num += luall;
}
cout << "平均查找长度为:" << endl;
cout << (double)(num / 15 )<< endl;
}
else {
for (int i = 0; i <= 13; i++) {
float luall = 0.0;
int test1 = d[i];
SearchBST2(tt, test1, luall);
num += luall;
}
cout << "平均查找长度为:" << endl;
cout << (double)(num / 14) << endl;
}
break;
case 6:
QianXvBianLi(preorderTraversal(tt));
if (Func(tt)) {
cout << "恭喜,是二叉排序树!" << endl;
}
else {
cout << "抱歉,不是二叉排序树~~~" << endl;
}
break;
}
} while (lu);
return 0;
}
#pragma once
#ifndef lgc
#define lgc
#include<iostream>
#include<string>
#include<vector>
#include <stdio.h>
#include <stdlib.h>
using namespace std;
#define element int
#define elementype char
#define keytype int
#define MAXLEN 200
#define rchild rChild
#define lchild lChild
int bin_search(element a[], int n, keytype x) {//基础二分法
int mid, low = 0, high = n - 1;//下标
while (low <= high) {
mid = low + high >> 1;
cout << mid << " ";
if (x == a[mid])return mid;
else if (x < a[mid])high = mid - 1;
else {
low = mid + 1;
}
}
return 0;
}
typedef struct Bnode {
element data;
struct Bnode* lChild, * rChild;
}btNode,biNode,bitree,BiNode ,*pB;
//已知二叉排序树为中序遍历递增树
Bnode* bst_search(Bnode* T, keytype x) {//非递归方式
Bnode* P = T;
while(P != NULL) {
if (x == P->data) {
return P;
}
else if (x < P->data) {
P = P->lChild;//来左子树这边
}
else {
P = P->rChild;
}
}
return P;
}
void bst_search2(Bnode* T, keytype x) {//非递归方式
Bnode* P = T;
while (P != NULL) {
if (x == P->data) {
cout << P->data << " ";
return;
}
else if (x < P->data) {
cout << P->data << " ";
P = P->lChild;//来左子树这边
}
else {
cout << P->data << " ";
P = P->rChild;
}
}
return ;
}
//<教材:将s插入T树中>
void insert(Bnode** T, Bnode* S) {//采用指针的指针
if (*T == NULL)*T = S;//插入点作为根节点
else if (S->data < (*T)->data) {
insert(&((*T)->lChild), S);//递归
}
else {
insert(&((*T)->rChild), S);
}
}
void strLTrim(char* str) {
int i, j;
int n = 0;
n = (int)strlen(str) + 1;
for (i = 0; i < n; i++) {
if (str[i] != ' ') //找到左起第一个非空格位置
break;
}
//以第一个非空格字符为手字符移动字符串
for (j = 0; j < n; j++) {
str[j] = str[i];
i++;
}
}
//卢氏垃圾读取文件法
void lu_find_read(elementype x[]) {
FILE* pFile; //定义二叉树的文件指针
char fileName[MAXLEN];
cout << "请输入对应的数据文件名ser.txt" << endl;
//char str[1000]; //存放读出一行文本的字符串
//char strTemp[10]; //判断是否注释行
cin >> fileName;//输入文件名
int err = fopen_s(&pFile, fileName, "r");
if (err != 0)
return;
if (!pFile) {
cout << "错误:文件" << fileName << "打开失败。" << endl;
return;
}
/*while (fgets(str, 1000, pFile) != NULL) { //跳过空行和注释行
strLTrim(str); //删除字符串左边空格
if (str[0] == '\n') //空行,继续读取下一行
continue;
strncpy_s(strTemp, str, 2);
//strTemp[1] = 0;
if (strstr(strTemp, "//") != NULL) //跳过注释行
continue;
else //非注释行、非空行,跳出循环
break;
}*/
/*while () {
char c = fgetc(pFile)
if (c!=',') {
}
}
if(char c = fgetc(pFile); //读取一个字符)
char c = fgetc(pFile); //读取一个字符
*/
fgets(x, 0xFF, pFile); //读取一行字符串
fclose(pFile);//关闭文件
}
//卢氏建树
void build(Bnode** t,elementype c[]) {
string s = "";
for (int i = 0; i < strlen(c); i++) {
if (c[i] != ',') {
s = s + c[i];
}
else {
int len = s.size();
int all = 0;
for (int j = 0; j < len; j++) {
all *= 10;
all += s[j] - '0';
}
s = "";
Bnode* ss = new Bnode;
ss->data = all;
ss->lChild = NULL;
ss->rChild = NULL;
//Bnode*sss = &ss;
insert(t, ss);//塞结点
}
}
}
//查找
Bnode SearchBST(Bnode* T, int key) {
//在根指针T所指二叉排序树中递归地查找某关键字等于key的数据元素
//若查找成功,则返回指向该数据元素结点的指针,否则返回空指针
if ((!T) || key == T->data) {
if (!T) {
cout << "查找失败" << endl;
return *T;
}
if (key == T->data) {
cout << "查找成功" << endl;
return *T;
}
} //查找结束
else if (key < T->data) return SearchBST(T->lchild, key); //在左子树中继续查找
else return SearchBST(T->rchild, key); //在右子树中继续查找
} // SearchBST
//查找+计数
Bnode *SearchBST2(Bnode* T, int key,float &lu_all) {
//在根指针T所指二叉排序树中递归地查找某关键字等于key的数据元素
//若查找成功,则返回指向该数据元素结点的指针,否则返回空指针
lu_all+=1;
if ((!T) || key == T->data) {
if (!T) {
cout << "查找失败" << endl;
return T;
}
if (key == T->data) {
cout << "查找成功" << endl;
return T;
}
} //查找结束
else if (key < T->data) return SearchBST2(T->lchild, key,lu_all); //在左子树中继续查找
else return SearchBST2(T->rchild, key,lu_all); //在右子树中继续查找
} // SearchBST
Bnode* FindMin(Bnode* BST)
{
if (BST == NULL) //树为空直接放回
return NULL;
else if (BST->lChild == NULL) //找到最左叶子结点并返回
return BST;
else
return FindMin(BST->lChild); //沿左分支继续递归查找
}
Bnode* Delete(Bnode* BST, int x)
{
Bnode* p;
if (BST == NULL) //如果树为空直接返回
return NULL;
else if (x < BST->data) //小于则左子树递归删除
BST->lChild = Delete(BST->lchild, x);
else if (x > BST->data) //大于则右子树递归删除
BST->rchild = Delete(BST->rchild, x);
else //等于则找到了要删除的结点
{
//如果被删除的结点有左、右两个孩子结点
if (BST->lchild && BST->rchild)
{
//找到右子树的最小元素
p = FindMin(BST->rchild);
//替代被删除的结点
BST->data = p->data;
//在被删除结点的右子树中删除刚才找到的右子树的最小元素
BST->rchild = Delete(BST->rchild, p->data);
}
//如果被删除结点只有一个孩子结点或没有孩子结点
else
{
p = BST;
if (BST->lchild == NULL) //有右孩子结点或没有孩子结点
BST = BST->rchild;
else if (BST->rchild == NULL) //有左孩子结点或没有孩子结点
BST = BST->lchild;
free(p); //释放结点
}
}
return BST;
}
bool Func(Bnode* T) {
if (T) {
if (NULL == T->lChild && NULL == T->rChild) {
return true;
}
else if (NULL == T->lChild) {
if (T->data < T->rChild->data) {
return Func(T->rChild);
}
else {
return false;
}
}
else if (NULL == T->rChild) {
if (T->data > T->lChild->data) {
return Func(T->lChild);
}
else {
return false;
}
}
else {
if (T->data < T->rChild->data && T->data > T->lChild->data) {
return (Func(T->rChild) && Func(T->lChild));
}
else {
return false;
}
}
}
}
vector<int> datas;
vector<int> preorderTraversal(btNode* root) {
if (root == nullptr) // 递归退出条件
return datas;
else
datas.push_back(root->data); // 递归遍历父节点,也是当前节点
preorderTraversal(root->lchild); // 递归遍历左子节点
preorderTraversal(root->rchild); // 递归遍历右子节点
return datas;
}
void QianXvBianLi(vector<int> datas) {
for (int i = 0; i < datas.size(); i++) {
cout << datas[i] << " ";
}
}
//按照实验四的方法构造树
// 删除字符串、字符数组左边空格
//从文本文件数据读入到数组中,同时返回实际结点数量
bool ReadFileToArray(char fileName[], char strLine[MAXLEN][3], int& nArrLen) {
//读文本文件数据到数组,返回数组及其长度
FILE* pFile; //定义二叉树的文件指针
char str[1000]; //存放读出一行文本的字符串
char strTemp[10]; //判断是否注释行
strTemp[9] = 0;
int err = fopen_s(&pFile, fileName, "r");
if (err != 0)
return false;
if (!pFile) {
cout << "错误:文件" << fileName << "打开失败。" << endl;
return false;
}
while (fgets(str, 1000, pFile) != NULL) { //跳过空行和注释行
strLTrim(str); //删除字符串左边空格
if (str[0] == '\n') //空行,继续读取下一行
continue;
strncpy_s(strTemp, str, 2);
//strTemp[1] = 0;
if (strstr(strTemp, "//") != NULL) //跳过注释行
continue;
else //非注释行、非空行,跳出循环
break;
}
//循环结束,str中应该已经是二叉树数据标识"BinaryTree",判断文件格式
cout << str << endl;
if (strstr(str, "BinaryTree") == NULL) {
cout << "错误:打开的文件格式错误!\n";
fclose(pFile); //关闭文件
return false;
}
nArrLen = 0; //数组行号初始化为0
while (fgets(str, 1000, pFile) != NULL) {
strLTrim(str); //删除字符串左边空格
if (str[0] == '\n') //空行,继续读取下一行
continue;
//注意
strncpy_s(strTemp, str, 2);
if (strstr(strTemp, "//") != NULL) //注释行,跳过,继续读取下一行
continue;
char* next_token = NULL;
char* token = NULL;
token = strtok_s(str, " ", &next_token); //以空格为分隔符,分割一行数据
if (token == NULL) { //分割为空串,失败退出
cout << "错误:读取二叉树结点数据失败!\n";
fclose(pFile); //关闭文件
return false;
}
strLine[nArrLen][0] = *token; //获取结点数据
token = strtok_s(NULL, " ", &next_token); //读取下一个子串,即此结点的左子树信息
if (token == NULL) { //分割为空串,失败退出
cout << "错误:读取二叉树结点数据失败!\n";
fclose(pFile); //关闭文件
return false;
}
strLine[nArrLen][1] = *token; //获取此结点的左子树信息数据
token = strtok_s(NULL, " ", &next_token); //读取下一个子串,即此结点的右子树信息
if (token == NULL) { //分割为空串,失败退出
cout << "错误:读取二叉树结点数据失败!\n";
fclose(pFile); //关闭文件
return false;
}
strLine[nArrLen][2] = *token; //获取此结点的右子树信息数据
nArrLen++; //数组行号加1
}
fclose(pFile); //关闭文件
return true;
}
//从数组创建二叉树--数组中保存的是二叉树的先序序列,及每个结点的子树信息
bool CreateBiTreeFromFile(btNode*& pBT, char strLine[MAXLEN][3], int nLen, int& nRow) {
//strLine[NODENUM][3]--保存节点数据的二维数组
//nLen--数组长度,即:节点个数
//nRow--数组当前行号
if ((nRow >= nLen) || (nLen == 0))
return false; //数据已经处理完毕,或者没有数据,退出
//根据数组数据递归创建子树
pBT = new btNode;
pBT->data = strLine[nRow][0];
pBT->lChild = NULL;
pBT->rChild = NULL;
int nRowNext = nRow; //保留本次递归的行号
if (strLine[nRowNext][1] == '1') { //当前结点有左子树,递归创建左子树,读下一行数据
nRow++;
CreateBiTreeFromFile(pBT->lChild, strLine, nLen, nRow);
}
if (strLine[nRowNext][2] == '1') { //当前结点有右子树,递归创建右子树,读下一行数组
nRow++;
CreateBiTreeFromFile(pBT->rChild, strLine, nLen, nRow);
}
return true;
}
//判定空树
bool isEmpty(btNode* T) {
if (T != NULL)
return false;
else
return true;
}
//中序遍历
void inorder(Bnode* root)
{
if (root == nullptr) {}
else {
if (root->lChild != nullptr)
inorder(root->lChild);
cout << root->data << ",";
if (root->rChild != nullptr)
inorder(root->rChild);
}
}
#endif // !lgc