AVL树

简介

在查找章节中提到了集合,集合分为动态集合静态集合,顺势引出顺序查找快表的概念。有了排序与快表,二分查找算法油然而生,进一步的衍生出融合了二分查找与顺序查找的分块查找。但是考虑到动态集合的频繁插入与删除操作,人们想出了二分查找树(BST)。可是BST的最坏情况令人无法接受,三位学者提出一种算法将BST结构限制为完全二叉树(AVL),这样频繁插入与删除时的效率大大提升。

AVL

逻辑

  • BST的插入与删除
  • 通过旋转保证完全二叉树结构

实现

#include <iostream>
#define SOURCE_ADDRESS "C:\\Users\\***\\Desktop\\AVLTreeInput.txt"
using namespace std;

struct Node {
    int data;
    Node *left, *right;
    int height;
};

Node* newNode(int data) {
    Node* node = new Node();
    node->data = data;
    node->left = NULL;
    node->right = NULL;
    node->height = 1;
    return node;
}

int getHeight(Node* node) {
    return node ? node->height : 0;
}

int getBalance(Node* node) {
    return node ? getHeight(node->left) - getHeight(node->right) : 0;
}

Node* leftRotate(Node* x) {
    Node* y = x->right;
    Node* z = y->left;

    x->right = z;
    y->left = x;

    x->height = 1 + max(getHeight(x->left), getHeight(x->right));
    y->height = 1 + max(getHeight(y->left), getHeight(y->right));

    return y;
}

Node* rightRotate(Node* x) {
    Node* y = x->left;
    Node* z = y->right;

    x->left = z;
    y->right = x;

    x->height = 1 + max(getHeight(x->left), getHeight(x->right));
    y->height = 1 + max(getHeight(y->left), getHeight(y->right));

    return y;
}

Node* insert(Node* node, int data) {
    if (!node) return newNode(data);
    if (data < node->data) node->left = insert(node->left, data);
    else if (data > node->data) node->right = insert(node->right, data);
    else return node;

    node->height = 1 + max(getHeight(node->left), getHeight(node->right));

    int balance = getBalance(node);
    // LL
    if (balance > 1 && data < node->left->data) return rightRotate(node);
    // LR
    if (balance > 1 && data > node->left->data) {
        node->left = leftRotate(node->left);
        return rightRotate(node);
    }
    // RR
    if (balance < -1 && data > node->right->data) return leftRotate(node);
    // RL
    if (balance < -1 && data < node->right->data) {
        node->right = rightRotate(node->right);
        return leftRotate(node);
    }

    return node;
}

Node* minValueNode(Node* node) {
    Node* current = node;
    while (current && current->left) current = current->left;
    return current;
}

Node* deleteNode(Node* root, int data) {
    if (!root) return root;

    // 执行正常的 BST 删除
    if (data < root->data) {
        root->left = deleteNode(root->left, data);
    } else if (data > root->data) {
        root->right = deleteNode(root->right, data);
    } else {
        // 节点只有一个子节点或没有子节点
        if (!root->left) {
            Node* temp = root->right;
            delete root; // 释放当前节点的内存
            return temp; // 返回右子节点
        } else if (!root->right) {
            Node* temp = root->left;
            delete root; // 释放当前节点的内存
            return temp; // 返回左子节点
        }

        // 节点有两个子节点,获取中序后继(最小节点)
        Node* temp = minValueNode(root->right);
        root->data = temp->data; // 替换数据
        root->right = deleteNode(root->right, temp->data); // 删除后继节点
    }

    // 更新高度
    root->height = 1 + max(getHeight(root->left), getHeight(root->right));

    // 重新平衡树
    int balance = getBalance(root);
    // LL
    if (balance > 1 && getBalance(root->left) >= 0) return rightRotate(root);
    // LR
    if (balance > 1 && getBalance(root->left) < 0) {
        root->left = leftRotate(root->left);
        return rightRotate(root);
    }
    // RR
    if (balance < -1 && getBalance(root->right) <= 0) return leftRotate(root);
    // RL
    if (balance < -1 && getBalance(root->right) > 0) {
        root->right = rightRotate(root->right);
        return leftRotate(root);
    }

    return root;
}

int sumNode = 0, sumSuc = 0; 
int treeHeight = 0;
void preOrderCountNodes(Node* node, int depth) {
    if (!node) return;
//    cout << node->data << " ";
	sumNode++;
	sumSuc += depth;
    preOrderCountNodes(node->left, depth+1);
    preOrderCountNodes(node->right, depth+1);
}

void output(){
	cout << "树高为:" << treeHeight << endl;
	cout << "共" << sumNode << "个顶点" << endl;
	printf("AVL=%3.2f\n", sumSuc * 1.0 / sumNode);
}

void preOrder(Node * node){
	if(!node)	return;
	
	cout << node->data << ' ';
	preOrder(node->left);
	preOrder(node->right);
}

int main() {
	Node* root = NULL;
	
	//file opeing
	FILE * f = fopen(SOURCE_ADDRESS, "r");
	if(f == NULL){
		cout << "file opening error" << endl;
		return 0;
	}
	//file operating
	char c;	int d;
	while(fscanf(f, " %c,%d", &c, &d) == 2){
		if(c == 'I'){
			root = insert(root, d);
		}else if (c == 'D'){
			root = deleteNode(root, d);
		}
		printf("c = %c, d = %d\n", c, d);
	}
	//file closing
	fclose(f);
	
	//outputing
	treeHeight = getHeight(root);
	
	preOrderCountNodes(root, 1);
	
	output();

    return 0;
}

代码对应课程实验,文件在文件夹
Reference https://zh.wikipedia.org/wiki/AVL树

posted @ 2024-11-22 20:54  luvmis  阅读(103)  评论(0)    收藏  举报