数据结构(HS)
树
一些概念说明:
Complete Binary tree --> 最后一层的结点需要从最左边开始填充
h=⌊log2n⌋h = \lfloor \log_2 n \rfloorh=⌊log2n⌋
Perfect Binary tree --> 最后一层的结点需要全部填满
h=log2(n+1)−1h = log_2(n+1) - 1h=log2(n+1)−1
Balanced binary tree --> 任意一个结点的左孩子和右孩子的高度差不能超过k,k经常取值为1
为什么要计算h,因为很多操作的复杂度和高度成正比
我们规定空树的高度为 -1
二叉树的实现方式
- 使用链表
- 使用数组(完全二叉树时,左孩子的下标是2i+12i+12i+1,右孩子的下标是2i+22i+22i+2)
二叉搜索树(BST)
查找,插入,删除的时间复杂度都是O(logn)O(logn)O(logn)
什么是二叉搜索树?
左孩子的值小于等于根结点,右孩子的值大于根结点
下面给出一个最基础的二叉搜索树
#include <stdio.h>
#include <stdlib.h>typedef struct node{int data;struct node *left;struct node *right;
}node;node *insert(node *root, int data){if(root == NULL){root = (node*)malloc(sizeof(node));root->data = data;root->left = NULL;root->right = NULL;}else if(data <= root->data){root->left = insert(root->left, data);}else{root->right = insert(root->right, data);}return root;
}int search(node *root, int data){if(root == NULL){return 0;}else if(data == root->data){return 1;}else if(data <= root->data){return search(root->left, data);}else{return search(root->right, data);}
}int main(){node *root = NULL;root = insert(root, 50);root = insert(root, 30);root = insert(root, 20);root = insert(root, 40);printf("Search 30: %d\n", search(root, 30));printf("Search 60: %d\n", search(root, 60));return 0;
}
Find height od a binary tree
高度的定义:该结点当叶子结点最长路径中边的数量
Height of tree = Height of root
Height of tree with 1 node = 0
深度的定义:该结点到根结点的路径中边的数量
int findHeight(node *root){if(root == NULL) return -1;int leftHeight = findHeight(root->left);int rightHeight = findHeight(root->right);return (leftHeight > rightHeight)? (leftHeight + 1) : (rightHeight + 1);}
Binary Tree Traversal
- Breadth -first
- Depth-first
- root-left-right 前序遍历
- left-root-right 中序遍历
- left-right-root 后序遍历
注:如果中序遍历用于二叉搜索树,那么打印出来的数据会是排序好的
层序遍历,使用队列可以实现,时间复杂度O(n)O(n)O(n),空间复杂度O(n)O(n)O(n)
void levelOrder(Tnode *root){if(root == NULL) return;Lnode *queue = (Lnode*)malloc(sizeof(Lnode));push(queue, root);while(!isEmpty(queue)){Tnode *temp = pop(queue);if(temp == NULL) break;printf("%d ",temp->data);if(temp->left != NULL) push(queue, temp->left);if(temp->right != NULL) push(queue, temp->right);free(temp);}}
深度优先(这个的空间复杂度取决于树的高度O(h)O(h)O(h)),这里的空间复杂度指的是栈空间,时间复杂度O(n)O(n)O(n)
void inOrder(Tnode *root){if(root == NULL) return;inOrder(root->left);printf("%d ",root->data);inOrder(root->right);}
删除结点
- 删除叶子结点,直接删除就好
- 只有一个孩子结点的情况:直接让该结点的父亲连接到该结点的孩子
- 当删除的结点有两个孩子的时候
- 将该结点的值改成左子树的最大值,然后去删这个最大值
- 将该结点的值改成右子树的最小值,然后去删这个最小值
- 上面两种情况二选一
Tnode* delete_Tnode(Tnode* root, int data){if(root == NULL) return NULL;if(data < root->data) root->left = delete_Tnode(root->left, data);else if(data > root->data) root->right = delete_Tnode(root->right, data);else{// in here we have found the node to be deleted//case 1 : no chileif(root->left == NULL && root->right == NULL){free(root);root = NULL;}//case 2 : one childelse if(root->left == NULL){Tnode* temp = root;root = root->right;free(temp);}else if(root->right == NULL){Tnode* temp = root;root = root->left;free(temp);}//case 3 : two childrenelse{// find the max value in the left subtree and replace the node's value with itroot->data = find_max(root->left);root = delete_Tnode(root->left, root->data);}}return root;
}
