Evelyn
QQ: 1809335179
假设树有n层,
有序树:子树有序,不可交换
完全二叉树:除了第n层和n-1外,其他各层的子结点数都达到最大值,即2^(n-1),且第n-1层的子结点数都集中在最左边。一般采用顺序存储结构。
满二叉树:除了第n层外,所有层的子结点数都达到最大值,即2^(n-1)个
二叉排序树:若左子树不为空时,左子树结点的值都小于根结点;右子树不为空时,右子树的值都大于跟节点;
二叉树的第 n层最多有2^(n-1)个子结点,整个二叉树最多有2^-1个子结点。任何一颗二叉树,度为 2 的子结点个数为k个,则度为 0 的子结点个数为k+1个。
红黑树:一种自平衡二叉查找树(平衡二叉树包括红黑树,AVL,SBT,伸展树,Treap),主要用来实现关联数组,他的查找、插入、删除操作时间复杂度均为log(n),进行这些操作后需要对数进行旋转,保证其平衡性,任何不平衡都会在三次旋转之内解决,但红黑树不追求完全平衡,典型的JDK 提供的集合类 TreeMap 本身就是一个红黑树的实现。 。
AVL树:是一种绝对的平衡二叉树,查找、插入、删除操作性能与红黑树一样。
一棵AVL树满足以下的条件:
1>它的左子树和右子树都是AVL树
2>左子树和右子树的高度差不能超过1
性质:
1>一棵n个结点的AVL树的其高度保持在0(log(n)),不会超过3/2log(n+1)
2>一棵n个结点的AVL树的平均搜索长度保持在0(log(n)).
3>一棵n个结点的AVL树删除一个结点做平衡化旋转所需要的时间为0(log(n)).
堆排序:大根堆和小根堆(要求是完全二叉树),大根堆(小根堆)任何一非叶节点的关键字不小于(不大于)其左右孩子节点的关键字。
前序遍历、中序遍历,后序遍历
前序遍历:根结点->左子树->右子树
中序遍历:左子树->根结点->右子树
后续遍历:左子树->右子树->根结点
void CreatTree(TreeNode* &tree, char *data,int length,int index) {//创建二叉树 if (index>=length) return ; tree = new TreeNode; tree->data = data[index]; tree->left = NULL; tree->right = NULL; CreatTree(tree->left, data, length, index*2+1 );//每一个子结点的index是根节点的2倍加1(左结点),2倍加2(右结点) CreatTree(tree->right, data, length, index*2+2); }
<pre name="code" class="cpp">typedef struct TreeNode { //结点结构 struct TreeNode *left; struct TreeNode *right; char data; }TreeNode; void preOrder(TreeNode *node) { // 前序遍历 if (node == NULL) return; printf("%c", node->data); preOrder(node->left); preOrder(node->right); } void inOrder(TreeNode *node) { // 中序遍历 if (node == NULL) return; inOrder(node->left); printf("%c", node->data); inOrder(node->right); } void postOrder(TreeNode *node) { // 后序遍历 if (node == NULL) return; postOrder(node->left); postOrder(node->right); printf("%c", node->data); }
非递归遍历方式;
void PreOrderNoRecurse(TreeNode* root) {
if (root == NULL)
return;
stack<TreeNode*> s;
TreeNode* p = root;
while (p != NULL || !s.empty()) {
while (p) {
s.push(p);
cout << p->data; //输出子树的根结点
p = p->left;
}
if(!s.empty()) { //这个用if而不用while,因为遍历完左节点直到为空后,先搜索当前结点的右结点,再判断这个右结点是否还存在左结点
p = s.top();
s.pop();
p= p ->right;
}
}
}
void inOrderNoRecurse(TreeNode* root) {
if (root == NULL)
return;
stack<TreeNode*> s;
TreeNode* p = root;
while (p != NULL || !s.empty()) {
while (p) {
s.push(p);
p = p->left;
}
if (!s.empty()) {
p = s.top();
s.pop(); //这一部分要写在这个循环内部,因为在根结点pop出以后栈为空,会是一个死循环。
cout << p->data; //跟前序遍历的区别,遍历完左结点后输出最后一个左结点,当前结点的左右节点都为空后从栈中回退节点
p = p->right;
}
}
}
void postOrderNoRecurse(TreeNode* root) {
if (root == NULL)
return;
stack<TreeNode*> s;
TreeNode* p = root;
s.push(root);
TreeNode* pre = NULL;
TreeNode* temp;
while ( !s.empty()) {
temp = s.top();
if ((temp->left == NULL && temp->right == NULL) || (pre != NULL && (pre == temp->left || pre == temp->right))) {
//当前结点左右结点为NULL或pre结点为当前结点的左结点或右结点时输出此结点
//因为是按右结点左结点的顺序压入栈的,所以这个判断说明已经没有子节点或者子节点已遍历完成并输出
cout << temp->data;
pre = temp;
s.pop();
}
else
{
if (temp->right)
s.push(temp->right);//这里是先压入右结点再压入左结点,因为栈是先入后出
if (temp->left)
s.push(temp->left);
}
}
}
不同遍历方式之间的相互转换
int PostOrderingfromPreMid(char* pre, char* mid, int length) {
/*已知前序遍历和中序遍历,得到后序遍历,在中序遍历中找到与前序遍历的头结点相等的结点 i ,则该结点的左边为左子树,结点个数为 i个, 右边为右子树,结点个数为 length-i-1个,此时在前序遍历中位置[1,i]为左子树,[i+1,length-1]为右子树,然后递归,因为后续遍历最后输出头节点,所以cout在最后。*\
int PostOrderingfromPreMid(char* pre, char* mid, int length) {
if (length <= 0)
return 0;
char temp = pre[0];
int i = 0;
for (; i < length; i++) {
if (mid[i] == temp)
break;
}
PostOrderingfromPreMid(pre + 1, mid, i);
PostOrderingfromPreMid(pre + i + 1, mid + i + 1, length - i - 1);
cout << temp;
return 1;
}
int PreOrderingfromMidPost(char* mid, char* post, int length) {
/*已知中序遍历和后续遍历,求出前序遍历,在中序遍历中找到与后序遍历的尾结点相等的结点 i (此结点为当前子树的根节点),则该结点的左边为左子树,结点个数为 i个, 右边为右子树,结点个数为 length-i-1个,此时在后序遍历中位置[0,i-1]为左子树,[i,length-1-1]为右子树,然后递归,因为前续遍历最先输出头节点,所以cout在最前<*/
if (length <= 0)
return 0;
char temp = post[length-1];
int i = 0;
for (; i < length; i++) {
if (mid[i] == temp)
break;
}
cout << temp;
PreOrderingfromMidPost(mid, post, i);
PreOrderingfromMidPost(mid +i+1, post + i, length - i - 1);
return 1;
}
已知前序遍历和中序遍历可以唯一确定一个二叉树;
已知后续遍历和中序遍历可以唯一确定一个二叉树;
但是已知前序遍历和后序遍历不能唯一确定一个二叉树;
不要特意记结点的元素,只要记清楚三个遍历的顺序,根据前后遍历跟结点在两端的特点,找出其在中序遍历的位置,然后可以知道左右子树的结点个数,然后递归就可以了。
void TraversebyLayer(TreeNode* tree) {//层序遍历
if (tree == NULL)
return;
vector<TreeNode*> node;
node.push_back(tree);
int count = 0; //记录当前遍历的节点在vector中的位置
//int t = node.size();
while (count < node.size()) {
if (node[count]->left)
node.push_back(node[count]->left);
if (node[count]->right)
node.push_back(node[count]->right);
count++;
}
for (int i = 0; i < node.size(); i++)
cout << node[i]->data;
cout << endl;
}