C语言 AVL平衡二叉查找树 插入/删除/遍历/查找

AVl树:平衡二叉查找树,树中任何节点的两个子树的高度最大差别为1。如下图所示

《C语言 AVL平衡二叉查找树 插入/删除/遍历/查找》

AVL树的查找、插入和删除在平均和最坏情况下都是O(logn)。
如果在AVL树中插入或删除节点后,使得高度之差大于1。此时,AVL树的平衡状态就被破坏,它就不再是一棵二叉树;为了让它重新维持在一个平衡状态,就需要对其进行旋转处理。

1. AVL树的结构

    typedef struct AVLTreeNode{
    Type key;                    // 关键字(键值)
    int height;                     //当前节点高度
    struct AVLTreeNode *left;    // 左孩子
    struct AVLTreeNode *right;    // 右孩子
}Node, *AVLTree;

2 AVL树的旋转操作

2.1 LL旋转

      LL旋转:左单旋。也称为”左左”。插入或删除一个节点后,根节点的左子树的左子树还有非空子节点,导致”根的左子树的高度”比”根的右子树的高度”大2,导致AVL树失去了平衡。如图所示:

《C语言 AVL平衡二叉查找树 插入/删除/遍历/查找》

 

     RR旋转:右单旋。也称为”右”。插入或删除一个节点后,根节点的右子树的右子树还有非空子节点,导致”根的右子树的高度”比”根的左子树的高度”大2,导致AVL树失去了平衡。如图所示:

《C语言 AVL平衡二叉查找树 插入/删除/遍历/查找》

    RL旋转:右双旋转。插入或删除一个节点后,根节点的右子树的左子树还有非空子节点,导致”根的右子树的高度”比”根的左子树的高度”大2,导致AVL树失去了平衡。如图所示:

《C语言 AVL平衡二叉查找树 插入/删除/遍历/查找》

 

    LR旋转:左双旋转。根节点的左子树的右子树还有非空子节点,导致”根的左子树的高度”比”根的右子树的高度”大2,导致AVL树失去了平衡。如图所示

《C语言 AVL平衡二叉查找树 插入/删除/遍历/查找》

3 代码实现:

先看avltree.h文件

#ifndef _AVL_TREE_H_
#define _AVL_TREE_H_

//AVL: 平衡二叉树
typedef int Type;

typedef struct AVLTreeNode{
	Type key;                    // 关键字(键值)
	int height;					 //当前节点高度
	struct AVLTreeNode *left;    // 左孩子
	struct AVLTreeNode *right;    // 右孩子
}Node, *AVLTree;

// 获取AVL树的高度
int avltree_height(AVLTree tree);

// 前序遍历"AVL树"
void preorder_avltree(AVLTree tree);
// 中序遍历"AVL树"
void inorder_avltree(AVLTree tree);
// 后序遍历"AVL树"
void postorder_avltree(AVLTree tree);

void print_avltree(AVLTree tree, Type key, int direction);

// (递归实现)查找"AVL树tree"中键值为key的节点
Node* avltree_search(AVLTree tree, Type key);
// (非递归实现)查找"AVL树tree"中键值为key的节点
Node* iterative_avltree_search(AVLTree tree, Type key);

// 查找最小结点:返回tree为根结点的AVL树的最小结点。
Node* avltree_minimum(AVLTree tree);
// 查找最大结点:返回tree为根结点的AVL树的最大结点。
Node* avltree_maximum(AVLTree tree);

// 将结点插入到AVL树中,返回根节点
Node* avltree_insert(AVLTree tree, Type key);

// 删除结点(key是节点值),返回根节点
Node* avltree_delete(AVLTree tree, Type key);

// 销毁AVL树
void destroy_avltree(AVLTree tree);


#endif

在看avltree.cpp文件

#include <stdio.h>
#include <stdlib.h>
#include "avltree.h"


#define HEIGHT(p)    ( (p==NULL) ? 0: (((Node *)(p))->height) )
#define MAX(a, b)    ( (a) > (b) ? (a) : (b) )

// 获取AVL树的高度
int avltree_height(AVLTree tree)
{
	return HEIGHT(tree);
}

// 前序遍历"AVL树" 先读取根节点,然后读取左子树,在读取右子树
void preorder_avltree(AVLTree tree)
{
	if (tree != NULL)
	{
		printf(" %d ", tree->key);
		preorder_avltree(tree->left);
		preorder_avltree(tree->right);
	}
}
// 中序遍历"AVL树" 先读取左子树,然后读取根节点,在读取右子树
void inorder_avltree(AVLTree tree)
{
	if (tree != NULL)
	{
		inorder_avltree(tree->left);
		printf(" %d ", tree->key);		
		inorder_avltree(tree->right);
	}
}
// 后序遍历"AVL树" 先读取左子树,然后读取右子树,在读取根节点
void postorder_avltree(AVLTree tree)
{
	if (tree != NULL)
	{
		postorder_avltree(tree->left);			
		postorder_avltree(tree->right);
		printf(" %d ", tree->key);	
	}
}

/*
 * 打印"AVL树"
 * tree       -- AVL树的节点
 * key        -- 节点的键值 
 * direction  --  0,表示该节点是根节点;
 *               -1,表示该节点是它的父结点的左孩子;
 *                1,表示该节点是它的父结点的右孩子。
*/
void print_avltree(AVLTree tree, Type key, int direction)
{
	if (tree != NULL)
	{
		if (direction == 0)
		{
			printf("%2d is root\n", tree->key, key);
		}
		else
		{
			printf("%2d is %2d's %6s child\n", tree->key, key, direction==1?"right" : "left");
		}

		print_avltree(tree->left, tree->key, -1);
		print_avltree(tree->right, tree->key, 1);
	}
}

// (递归实现)查找"AVL树x"中键值为key的节点
Node* avltree_search(AVLTree tree, Type key)
{
	if (tree==NULL || tree->key == key)
	{
		return tree;
	}

	if (tree->key > key) //小于根节点
	{
		avltree_search(tree->left, key);
	}
	else
	{
		avltree_search(tree->right, key);
	}
}
// (非递归实现)查找"AVL树x"中键值为key的节点
Node* iterative_avltree_search(AVLTree tree, Type key)
{
	while ((tree!=NULL) && (tree->key != key))
	{
		if (tree->key > key)
		{
			tree = tree->left;
		}
		else
		{
			tree = tree->right;
		}
	}
	return tree;
}

// 查找最小结点:返回tree为根结点的AVL树的最小结点。avl是有序树,所以查找左子树叶节点即可
Node* avltree_minimum(AVLTree tree)
{
	if (tree == NULL)
	{
		return NULL;
	}
	while (tree->left != NULL)
	{
		tree = tree->left;
	}

	return tree;
}
// 查找最大结点:返回tree为根结点的AVL树的最大结点。与最小节点相反查找右子树叶节点
Node* avltree_maximum(AVLTree tree)
{

	if (tree == NULL)
	{
		return NULL;
	}
	while (tree->right != NULL)
	{
		tree = tree->right;
	}

	return tree;
}

/*创建节点
 *left 新节点的左叶节点
 *right 新节点的右叶节点
*/
static Node* Create_AVLtree_Node(Type key, Node* left, Node* right)
{
	Node* pNode = (Node*)malloc(sizeof(Node));
	if (pNode == NULL)
	{
		return NULL;
	}

	pNode->key = key;
	pNode->height = 0;
	pNode->left = left;
	pNode->right = right;

	return pNode;
}

/* 
 * LL : 左单旋转
 * 返回值:旋转后的根节点
*/
static Node* left_left_rotation(AVLTree k2)
{
	AVLTree k1;
	k1 = k2->left;
	k2->left  = k1->right;
	k1->right = k2;

	k2->height = MAX(HEIGHT(k2->left), HEIGHT(k2->right))+1;
	k1->height = MAX(HEIGHT(k1->left), k2->height)+1;

	return k1;
}

/* 
 * RR : 右单旋转
 * 返回值:旋转后的根节点
*/
static Node* right_right_rotation(AVLTree k1)
{
	AVLTree k2;
	k2 = k1->right;
	k1->right  = k2->left;
	k2->left = k1;

	k1->height = MAX(HEIGHT(k1->left), HEIGHT(k1->right))+1;
	k2->height = MAX(HEIGHT(k2->right), k1->height)+1;

	return k2;
}

/* 
 * LR : 左双旋转
 * 返回值:旋转后的根节点
*/
static Node* left_right_rotation(AVLTree k3)
{
	k3->left = right_right_rotation(k3->left);

	return left_left_rotation(k3);
}

/* 
 * RL : 右双旋转
 * 返回值:旋转后的根节点
*/
static Node* right_left_rotation(AVLTree k1)
{
	k1->right = left_left_rotation(k1->right);

	return right_right_rotation(k1);
}

/* 将结点插入到AVL树中,返回根节点
* tree  AVL树根节点
* key   插入的节点的键值
* 返回值:根节点
*/
Node* avltree_insert(AVLTree tree, Type key)
{
	if (tree == NULL)
	{
		tree = Create_AVLtree_Node(key, NULL, NULL);
		if (tree == NULL)
		{
			printf("create Node fail\n");
			return NULL;
		}
	}
	else if (key > tree->key) //大于根节点,插入右子树
	{
		tree->right = avltree_insert(tree->right, key);
		if (HEIGHT(tree->right) - HEIGHT(tree->left) == 2)
		{
			if (key > tree->right->key)
			{
				tree = right_right_rotation(tree);
			}
			else
			{
				tree = right_left_rotation(tree);
			}
		}
	}
	else if(key < tree->key)
	{
		tree->left = avltree_insert(tree->left, key);
		if (HEIGHT(tree->left) - HEIGHT(tree->right) == 2)
		{
			if (key < tree->left->key)
			{
				tree = left_left_rotation(tree);
			}
			else
			{
				tree = left_right_rotation(tree);
			}
		}
	}
	else
	{
		printf("don't allow insert the same value\n");
	}

	tree->height = MAX( HEIGHT(tree->left), HEIGHT(tree->right)) + 1;

	return tree;
}


/* 
* tree  AVL树根节点
* key   要删除的节点的键值
* 返回值:新根节点
*/
static Node* delteNode(AVLTree tree, Node* pdel)
{
	if (tree == NULL || pdel == NULL)
	{
		return NULL;
	}

	if (pdel->key < tree->key) //删除节点在左子树
	{
		tree->left = delteNode(tree->left, pdel);
		if (HEIGHT(tree->right) - HEIGHT(tree->left) == 2)
		{
			Node* pRTemp = tree->right;
			//调整平衡
			if (HEIGHT(pRTemp->left) > HEIGHT(pRTemp->right))
			{
				tree = right_left_rotation(pRTemp);
			}
			else
			{
				tree = right_right_rotation(pRTemp);
			}
		}
	}
	else if(pdel->key > tree->key) //删除节点在右子树
	{
		tree->right = delteNode(tree->right, pdel);
		if (HEIGHT(tree->left) - HEIGHT(tree->right) == 2)
		{
			Node* pLTemp = tree->left;
			if (HEIGHT(pLTemp->right) > HEIGHT(pLTemp->left))
			{
				tree = left_right_rotation(pLTemp);
			}
			else
			{
				tree = left_left_rotation(pLTemp);
			}
		}
	}
	else  //当前根节点就是要删除的节点
	{
		//节点左右孩子为空
		if ((tree->left) && (tree->right))
		{
			if (HEIGHT(tree->left) > HEIGHT(tree->right))
			{
				//左子树比右子树搞,找出tree的左子树最大节点,将该最大节点的值付给tree,然后该最大节点
				Node* maxnode = avltree_maximum(tree->left);
				tree->key = maxnode->key;
				tree->left = delteNode(tree->left, maxnode);
			}
			else
			{
				//如果左子树不比右子树高,找出tree右子树中的最小节点,将最小节点的值赋给tree,删除该最小节点
				Node* minnode = avltree_minimum(tree->right);
				tree->key = minnode->key;
				tree->right = delteNode(tree->right, minnode);
			}
		}
		else
		{
			Node* pTemp = tree;
			tree = tree->left ? tree->left : tree->right;
			free(pTemp);
		}
	}

	return tree;
}
// 删除结点(key是节点值),返回根节点
Node* avltree_delete(AVLTree tree, Type key)
{
	Node* pTmp;

	if ((pTmp = avltree_search(tree, key)) != NULL)
	{
		tree = delteNode(tree, pTmp);
	}
	return tree;
}

// 销毁AVL树
void destroy_avltree(AVLTree tree)
{
	if (tree == NULL)
	{
		return;
	}
	if (tree->left != NULL)
	{
		destroy_avltree(tree->left);
	}
	if (tree->right != NULL)
	{
		destroy_avltree(tree->right);
	}

	free(tree);
}

在看测试代码main.cpp

#include <stdio.h>
#include <iostream>
#include "avltree.h"

static int arr[]= {3,2,1,4,5,6,7,16,15,14,13,12,11,10,8,9};
#define TBL_SIZE(a) ( (sizeof(a)) / (sizeof(a[0])) )

int main()
{
    int i,ilen;
    AVLTree root=NULL;

    printf(" 高度: %d\n", avltree_height(root));
    printf(" 依次添加: ");
    ilen = TBL_SIZE(arr);
    for(i=0; i<ilen; i++)
    {
        printf("%d ", arr[i]);
        root = avltree_insert(root, arr[i]);
    }

    printf("\n 前序遍历: ");
    preorder_avltree(root);

    printf("\n 中序遍历: ");
    inorder_avltree(root);

    printf("\n 后序遍历: ");
    postorder_avltree(root);
    printf("\n");

    printf(" 高度: %d\n", avltree_height(root));
    printf(" 最小值: %d\n", avltree_minimum(root)->key);
    printf(" 最大值: %d\n", avltree_maximum(root)->key);
    printf(" 树的详细信息: \n");
    print_avltree(root, root->key, 0);


    i = 8;
    printf("\n 删除根节点: %d", i);
    root = avltree_delete(root, i);

    printf("\n 高度: %d", avltree_height(root));
    printf("\n 中序遍历: ");
    inorder_avltree(root);
    printf("\n 树的详细信息: \n");
    print_avltree(root, root->key, 0);

    // 销毁二叉树
    destroy_avltree(root);

	system("pause");
	return 0;
}

最后看测试结果:

《C语言 AVL平衡二叉查找树 插入/删除/遍历/查找》

4 图解操作

4.1 插入操作

《C语言 AVL平衡二叉查找树 插入/删除/遍历/查找》

这就是以上代码插入的结果示意图。

前序遍历结果:7 4 2 1 3 6 5 13 11 9 8 10 12 15 14 16

中序遍历结果:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

后序遍历结果:1 3 2 5 6 4 8 10 9 12 11 14 16 15 13 7 

树的深度为 5

最大值为 16

最下值为 1

4.2 删除操作

《C语言 AVL平衡二叉查找树 插入/删除/遍历/查找》

删除节点 8

中序遍历结果 :1 2 3 4 5 6 7 9 10 11 12 13 14 15 16

以上就是所有的代码和结果,如果程序中有不严谨的地方,请在下方留言。

    原文作者:二叉查找树
    原文地址: https://blog.csdn.net/HardessGod/article/details/84991775
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞