树
1.树的基本操作
-
查找:先取根结点,如果它等于我们要查找的数就返回;如果查找的数据比根节点小,就在左子树中递归查找;如果要查找的数据比根结点大,那么就在右子树中递归查找。
-
插入:如果要插入的数据比结点大,并且结点的右子树为空,就将新数据直接插到右孩子的位置;如果不为空,就再递归遍历右子树,查找插入位置。同理,如果要插入的数据比结点小,并且结点的左子树为空,就将新数据插入到左孩子的位置;如果不为空,就再递归遍历左子树,查找插入位置。
-
删除:分三种情况处理
a. 如果要删除结点没有孩子,那么直接将该结点删除就行了。
b. 如果要删除结点只有一个孩子,那么需要就父亲结点对应的指针,指向孩子结点。
c. 如果要删除结点有两个孩子,那么我们可以找到这个结点的右子树中最小结点 (或者 左子树中最大结点),把它替换到要删除的结点上,然后再删除掉这个最小结点。
2.遍历
- 深度优先搜索遍历
- 先序DLR
- 中序LDR
- 后序LRD
- 广度优先遍历
- 将根节点入队列
- 判断队列是否为空
- 是:结束遍历
- 否:出队列(判断出对队列的结点是否有左孩子,有:将左孩子入队列;判断是否有右孩子,有:将右孩子出对列)返回2
结论:树的增删查的时间复杂度为O(h),h为树的高度。
问题:根为第一层
- n个结点,高度最低为多少?
完全二叉树, log(n+1) - n个节点的完全二叉树,其高度为多少?
log(n+1)向上取整 - 高度为h的二叉树,节点数目范围是
2h-1 ~~2h-1
二叉树的基本操作 中序遍历 层次遍历
BST.h
#pragma once
#include<stdbool.h>
typedef char K;
typedef struct tree_node {
K key;
struct tree_node* left;
struct tree_node* right;
}TreeNode;
typedef struct {
TreeNode* root;
}BST;
//API
BST* bst_create();
bool bst_insert(BST* tree, K key);
bool bst_find(BST* tree, K key);
bool bst_delete(BST* tree, K key);
Queue.h
#pragma once
#include<stdbool.h>
#define N 10
typedef struct tree_node* E;
typedef struct {
E elements[N];
int front;
int rear;
int size;
}Queue;
Queue* create_queue();
void destroy_queue(Queue* q);
void enqueue(Queue* q, E val);
E dequeue(Queue* q);
E peek(Queue* q);
int size(Queue* q);
bool isEmpty(Queue* q);
bool isFull(Queue* q);
BST.c
#include "BST.h"
#include"Queue.h"
#include <stdio.h>
#include<stdlib.h>
BST* bst_create() {
return calloc(1, sizeof(BST));
}
bool bst_insert(BST* tree, K key) {
TreeNode* parent = NULL;
TreeNode* curr = tree->root;
int cmp = 0;
while (curr != NULL) {
cmp = key - curr->key;
if (cmp == 0) {
return false;
}
else if (cmp < 0) {//往左走
parent = curr;
curr = curr->left;
}
else { //往右走
parent = curr;
curr = curr->right;
}
}
//插入结点
TreeNode* newNode = (TreeNode*)calloc(1, sizeof(TreeNode));
if (newNode == NULL) {
printf("calloc failed in bst_insert\n");
exit(1);
}
//初始化
newNode->key = key;
//链接
if(parent==NULL){//空树
tree->root = newNode;
}
else if (cmp < 0) {
parent->left = newNode;
}
else {
parent->right = newNode;
}
return true;
}
bool bst_find(BST* tree, K key) {
TreeNode* curr = tree->root;
while (curr != NULL) {
int cmp = key - curr->key;
if (cmp == 0) {
return true;
}
else if (cmp < 0) {
curr = curr->left;
}
else {
curr = curr->right;
}
}
//不存在
return false;
}
bool bst_delete(BST* tree, K key) {
//找到要删除的结点
TreeNode* parent = NULL;
TreeNode* curr = tree->root;
while (curr != NULL) {
int cmp = key - curr->key;
if (cmp == 0) {
break;
}
else if (cmp<0 ){//往左走
parent = curr;
curr = curr->left;
}
else {
parent = curr;
curr = curr->right;
}
}
if (curr == NULL) {
return false;
}
//删除cur指向的节点
//将度为 degree=2的情况退化成degree=0或者degree=1
if (curr->left != NULL && curr->right != NULL) {
//找右子树最小结点
TreeNode* minParent = curr;
TreeNode* minOfRight = curr->right;
while (minOfRight->left != NULL) {
minParent = minOfRight;
minOfRight = minOfRight->left;
}
//替换值
curr->key = minParent->key;
//退化
parent = minParent;
curr = minOfRight;
}
//处理degree=1和degree=0
//删除curr指向的结点
TreeNode* child = curr->left ? curr->left : curr->right;
if (parent == NULL) {
tree->root = child;//删除根结点
}
else if (curr->key - parent->key < 0) {
parent->left = child; //将为唯一的子树链接到parent的左边
}
else {
parent->right = child; //将唯一的子树链接到parent的右边
}
free(curr);
return true;
}
//中序遍历
void inorder(TreeNode* node) {
if (node == NULL)return;
//递归公式
//遍历左子树
inorder(node->left);
//遍历根结点
printf("%c ", node->key);
//遍历右子树
inorder(node->right);
}
void bst_inorder(BST* tree) {
//委托
inorder(tree->root);
printf("\n");
}
void bst_levelorder(BST* tree) {
if (tree->root == NULL)return;
Queue* q = create_queue();
//将根节点入队列
enqueue(q, tree->root);
//判断队列是否为空
while (!isEmpty(q)) {
TreeNode* node = dequeue(q);
printf("%c", node->key);
//判断是否有左孩子
if (node->left != NULL) {
enqueue(q, node->left);
}
//判断是否有右孩子
if (node->right != NULL) {
enqueue(q, node->right);
}
}
printf("\n");
destroy_queue(q);
}
Queue.c
#include "Queue.h"
#include<stdlib.h>
#include<stdio.h>
Queue* create_queue() {
return calloc(1, sizeof(Queue));
}
void destroy_queue(Queue* q) {
free(q);
}
bool isEmpty(Queue* q) {
return q->size == 0;
}
bool isFull(Queue* q) {
return q->size == N;
}
void enqueue(Queue* q, E val) {
//判满
if (isFull(q) ){
return;
}
//添加到队尾
q->elements[q->rear] = val;
q->rear = (q->rear + 1) % N;
q->size++;
}
E dequeue(Queue* q) {
//判空
if (isEmpty(q)) {
printf("Error: empty queue\n");
exit(1);
}
E result = q->elements[q->front];
q->front = (q->front + 1) % N;
q->size--;
return result;
}
E peek(Queue* q) {
if (isEmpty(q)) {
printf("Error: empty queue\n");
exit(1);
}
return q->elements[q->front];
}
int size(Queue* q) {
return q->size;
}
main.c
#include"BST.h"
int main(void) {
BST* tree = bst_create();//空树
bst_insert(tree, 'M'); //M
bst_insert(tree, 'B'); //B P
bst_insert(tree, 'P'); //K
bst_insert(tree, 'K');
bst_insert(tree, 'B');
/*printf("%s\n", bst_find(tree, 'p') ? "true" : "false");
printf("%s\n", bst_find(tree, 'x') ? "true" : "false");
printf("%s\n", bst_delete(tree, 'm') ? "true" : "false");
printf("%s\n", bst_delete(tree, 'x') ? "true" : "false");*/
bst_inorder(tree);
/*bst_levelorder(tree);*/
return 0;
}
3.平衡二叉搜索树
AVL:任意一个结点,其左子树和右子树高度之差不能超过1。
红黑树:h=log(n)
红黑树