前言:《数据结构》作为计算机专业的一门重点学科,无论是将来考研、就业,对其的考察都是重中之重,之前的文章已经对此进行过论述。作为考察程序员“编程能力”的一种方式,考验的是我们如何将数据结构的思想用编程语言精确的编码出来。所有的《数据结构》课本都详细的讲解了每一种数据结构和算法的思想,然后给出具体的编程语言代码或者伪代码。算法思想只要认真看书,还是比较容易掌握的 ,真正考验我们的,是从算法思想到具体编码的这个思考过程,就是思考如何编码实现,这个过程是逃不掉的,除非参考别人的现有代码,但一段时间过后一定会忘记(百分之百的,我就忘记了无数次了)。所以,尽量在编程实现前,自己有个清晰的思路,尝试
着自己去实现,然后调试,脑细胞不够用了再去参考别人写的。
0、代码:本文全部代码放在 github:https://github.com/thinkChao/Data-Structure/blob/master/%E4%BA%8C%E5%8F%89%E6%A0%91.cpp 中,需要的可以下载或者直接复制代码运行,只有一个cpp文件。已经通过测试,完全没有问题。
1、定义二叉树的节点
struct Node
{
int value;
struct Node *left_node;
struct Node *right_node;
};
typedef struct Node TNode; //定义二叉树节点 (方式一)
typedef TNode *BTree; //定义二叉树链表(方式二)
二叉树的节点定义很简单,采用结构体,一个数据域和两个指针域。但有一个问题是让我不解的,就是为什么在typedef时要采用两种方式,而且我看过的所有课本中,无一例外的都采用了这两种方式(在链表的定义中也是如此)。我试验只采用第一种,完全没任何问题。我去网上搜索,也没人给出答案。看到这篇文章的同学,如果知道的话,希望留言告诉我,不胜感激!
2、二叉树的建立
思路:一般的题目中,都是直接告诉我们有一棵二叉树,直接让我们进行各种遍历,让我们从零创建一棵树的还真不多见。仔细想想,思路还真不是那么清晰。如果说给我们两种遍历的结果,让我们反推这棵树,那结果是唯一的。但直接给我们一个数组,让我们创建一棵二叉树,那创建的方式太多了,一时还真没啥思路。不过翻看了一本书,书中给了一种创建过程,他采用的原则是“小于父节点的值放在左子树,大于父节点的值放在右子树”。但是,让我困惑的是,他说“建立二叉树必须遵守这个原则”,我怎么从来没听说过这个原则???这个先不管了,不过这是创建二叉树的一种方式,总算有个可以依据的原则,接下来就创建吧。
void Add_Node(int value)
{
/*定义需要用到的变量*/
TNode *newNode; //待插入的新节点
BTree currentNode; //临时的指针
int flag = 0; //记录是否插入了新的节点
newNode = (TNode *)malloc(sizeof(TNode)); //为新节点分配空间并输入内容
newNode->value = value;
newNode->left_node = NULL;
newNode->right_node = NULL;
/*将新节点插入二叉树*/
if(bTree == NULL)
bTree = newNode;
else
{
currentNode = bTree;
while(!flag) //循环结束的时刻是:flag=1,即节点已被插入
{
if(value<currentNode->value)
{
if(currentNode->left_node==NULL)
{
currentNode->left_node=newNode;
flag=1;
}
else
currentNode=currentNode->left_node;
}
else
{
if(currentNode->right_node==NULL)
{
currentNode->right_node=newNode;
flag=1;
}
else
currentNode=currentNode->right_node;
}
}
}
}
int main()
{
int content[ArraySize];
cout<<"请输入6个整数:"<<endl; //输入数据
for(int i=0;i<ArraySize;i++)
cin>>content[i];
for(i=0;i<ArraySize;i++) //建树
Add_Node(content[i]);
return 0;
}
3、三种遍历方式(递归&非递归):直接上代码吧,注释还比较详细,不明白的地方可以留言。
void Preorder(BTree bTree) //递归前序遍历
{
if(bTree!=NULL)
{
cout<<bTree->value<<" ";
Preorder(bTree->left_node);
Preorder(bTree->right_node);
}
}
void Preorder2(BTree bTree) //非递归前序遍历
{
/*定义需要用到的变量*/
BTree stack[ArraySize]; //用数组来充当栈
int top=0; //top变量来充当栈顶指针,top为0说明栈空
BTree p=bTree;
while(p||top!=0)
{
if(p)
{
cout<<p->value<<" ";
stack[top++]=p;
p=p->left_node;
}
else
{
p=stack[--top]; //注意这里是“--top”
p=p->right_node;
}
}
}
void Inorder(BTree bTree) //递归中序遍历
{
if(bTree!=NULL)
{
Inorder(bTree->left_node);
cout<<bTree->value<<" ";
Inorder(bTree->right_node);
}
}
void Inorder2(BTree bTree) //非递归中序遍历
{
/*定义需要用到的变量*/
BTree stack[ArraySize]; //用数组来充当栈
int top=0; //top变量来充当栈顶指针,top为0说明栈空
BTree p=bTree;
while(p||top!=0) //举例:建立一个只有三个节点的二叉树发现,当p的指向为空,且top=0的时候,所有的元素都已经遍历过了
{
if(p)
{
stack[top++]=p;
p=p->left_node;
}
else //举例发现,当p指向为空时,就要执行出战操作,然后输出元素
{
p=stack[--top]; //注意这里是“--top”
cout<<p->value<<" ";
p=p->right_node;
}
}
}
void Postorder(BTree bTree) //递归后序遍历
{
if(bTree!=NULL)
{
Postorder(bTree->left_node);
Postorder(bTree->right_node);
cout<<bTree->value<<" ";
}
}
void Postorder2(BTree bTree) //非递归后序遍历
{
BTree stack1[ArraySize];
int stack2[ArraySize];
int top1=0,top2=0;
int flag;
BTree p=bTree;
while(p||top1!=0)
{
if(p)
{
stack1[top1++]=p;
stack2[top2++]=0;
p=p->left_node;
}
else
{
p=stack1[top1-1];
flag=stack2[top2-1];
if(flag==0)
{
stack2[top2-1]=1;
p=p->right_node;
}
else
{
p=stack1[--top1];
--top2;
cout<<p->value<<" ";
p=NULL; //这一句很关键,调试了一上午,问题就是没有加上这一句。
}
}
}
}