堆:
是完全二叉树,不适合链式存储的树
大顶堆(大根堆):
根节点比左右子树大
小顶堆(小根堆):
根节点比左右子树小
数据项:
存储数据的内存首地址
容量
数量
运算:
创建、销毁、添加、删除、空堆、满堆、堆顶
83 86 77 15 93 35 86 92 49 21
堆结构的删除:
1、堆顶与末尾元素交换,删除末尾
2、对新堆顶从上往下重新调整成堆结构
堆的应用:
1、堆排序
不停地重复执行删除堆顶的操作,直到删除全部元素,最终整个存储元素的内存就有序了
2、优先队列
在优先队列中,元素被赋予优先级。当访问元素时,具有最高优先级的元素最先删除。优先队列具有最高级先出的行为特征
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define TYPE int
#define SWAP(a,b) {typeof(a) t=(a);(a)=(b);(b)=t;}
// 大顶堆
typedef struct Heap
{
TYPE* arr;
size_t cal;
size_t cnt;
}Heap;
// 创建
Heap* create_heap(int cal)
{
Heap* heap = malloc(sizeof(Heap));
heap->arr = malloc(sizeof(TYPE)*cal);
heap->cal = cal;
heap->cnt = 0;
return heap;
}
// 空堆
bool empty_heap(Heap* heap)
{
return 0 == heap->cnt;
}
// 满堆
bool full_heap(Heap* heap)
{
return heap->cnt >= heap->cal;
}
// 添加
bool add_heap(Heap* heap,TYPE data)
{
if(full_heap(heap)) return false;
heap->arr[heap->cnt++] = data;
// 新加入的位置进行调整成大顶堆
int index = heap->cnt; // 编号
while(index > 1)
{
if(heap->arr[index/2-1] < heap->arr[index-1])
{
SWAP(heap->arr[index/2-1],heap->arr[index-1]);
index /= 2;
continue;
}
return true;
}
return true;
}
void show_heap(Heap* heap)
{
for(int i=0; i<heap->cnt; i++)
{
printf("%d ",heap->arr[i]);
}
printf("\n");
}
// 删除堆顶
bool del_top_heap(Heap* heap)
{
if(empty_heap(heap)) return false;
// 堆顶与末尾交换
SWAP(heap->arr[0],heap->arr[heap->cnt-1]);
// 删除末尾
heap->cnt--;
// 从上到下重新调整成堆结构
int index = 1;
while(index <= heap->cnt)
{
// 有右子树,比较左右,谁大再与根比较,根小则交换
if(index*2 < heap->cnt)
{
// 右比左大
if(heap->arr[index*2] > heap->arr[index*2-1])
{
// 根小 交换右和根
if(heap->arr[index*2] > heap->arr[index-1])
{
SWAP(heap->arr[index*2],heap->arr[index-1]);
index = index*2+1;
}
else
return true;
}
else //左 大于等于 右
{
if(heap->arr[index*2-1] > heap->arr[index-1])
{
SWAP(heap->arr[index*2-1],heap->arr[index-1]);
index = index*2;
}
else
return true;
}
}
else if(index*2-1 < heap->cnt)// 只有左子树
{
if(heap->arr[index*2-1] > heap->arr[index-1])
{
SWAP(heap->arr[index*2-1],heap->arr[index-1]);
index = index*2;
}
else
return true;
}
else
return true;
}
}
// 堆排序
void sort_heap(int* arr,int len)
{
// 把数组调整成大顶堆结构
for(int i=1; i<len; i++)
{
int index = i+1; //编号
while(index > 1)
{
if(arr[index-1] > arr[index/2-1])
{
SWAP(arr[index-1],arr[index/2-1]);
index = index/2;
}
else
break;
}
}
// 交换堆顶与末尾,有效个数-1,重新调整堆结构,直到有效个数为0
while(len > 1)
{
SWAP(arr[0],arr[len-1]);
len--;
//从上往下调整
int index = 1; //编号
while(index-1 < len)
{
if(index*2 < len) //有右
{
// 右最大 交换根和右
if(arr[index*2] > arr[index*2-1])
{
if(arr[index*2] > arr[index-1])
{
SWAP(arr[index*2],arr[index-1]);
index = index*2+1;
}
else
break;
}
else // 左大于等于右
{
if(arr[index*2-1] > arr[index-1])
{
SWAP(arr[index*2-1],arr[index-1]);
index = index*2;
}
else
break;
}
}
else if(index*2-1 < len) //只有左
{
if(arr[index*2-1] > arr[index-1])
{
SWAP(arr[index*2-1],arr[index-1]);
index = index*2;
}
else
break;
}
else
break;
}
}
}
// 从top下标 到end下标 向下调整成堆结构
void _sort_heap(int* arr,int top,int end)
{
if(top >= end) return;
int max = top+1; //编号
int l = max*2; //左子树编号
int r = max*2+1; //右子树编号
if(l-1 <= end && arr[l-1] > arr[max-1]) //有左
{
max = l;
}
if(r-1 <= end && arr[r-1] > arr[max-1]) //有右
{
max = r;
}
if(max != top+1)
{
// 值最大的不是根,则交换
SWAP(arr[max-1],arr[top]);
_sort_heap(arr,max-1,end);
}
}
// 堆排序递归实现
void sort_heap_recursion(int* arr,int len)
{
// 把数组调整成大顶堆结构
for(int i=1; i<len; i++)
{
int index = i+1; //编号
while(index > 1)
{
if(arr[index-1] > arr[index/2-1])
{
SWAP(arr[index-1],arr[index/2-1]);
index = index/2;
}
else
break;
}
}
for(int i=len-1; i>0; i--)
{
SWAP(arr[0],arr[i]);
_sort_heap(arr,0,i-1);
}
}
int main(int argc,const char* argv[])
{
int arr[10] = {};
for(int i=0; i<10; i++)
{
arr[i] = rand()%100;
}
sort_heap_recursion(arr,10);
for(int i=0; i<10; i++)
{
printf("%d ",arr[i]);
}
/*
Heap* heap = create_heap(10);
for(int i=0; i<10; i++)
{
add_heap(heap,rand()%100);
}
show_heap(heap);
del_top_heap(heap);
show_heap(heap);
*/
}
平衡二叉树:
前提是一棵有序二叉树,它的左右子树高度差不超过1,同时它的所有子树也要满足该条件
二叉树不平衡的四种基础原因:
x y
/ \ / \
y t1 z x
/ \ / \ / \
z t2 以y为轴右旋转 t3 t4 t2 t1
/ \
t3 t4
x y
/ \ / \
t1 y x z
/ \ 以y为轴左旋转 / \ / \
t2 z t1 t2 t3 t4
/ \
t3 t4
x x z
/ \ / \ / \
y t1 z t1 y x
/ \ / \ / \ / \
t2 z y t4 t2 t3 t4 t1
/ \ / \
t3 t4 t2 t3
以z为轴左旋转 以z为轴右旋转
x x z
/ \ / \ / \
t1 y t1 z x y
/ \ / \ / \ / \
z t2 t3 y t1 t3 t4 t2
/ \ / \
t3 t4 t4 t2
以z为轴右旋转 以z为轴左旋转
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct TreeNode
{
int data;
struct TreeNode* left;
struct TreeNode* right;
}TreeNode;
// 创建节点
TreeNode* create_node(int data)
{
TreeNode* node = malloc(sizeof(TreeNode));
node->data = data;
node->left = NULL;
node->right = NULL;
return node;
}
// 求高度
int high_tree(TreeNode* root)
{
if(NULL == root) return 0;
int lh = high_tree(root->left);
int rh = high_tree(root->right);
return lh>rh ? lh+1 : rh+1;
}
// 左右子树高度差
int diff_high(TreeNode* root)
{
return high_tree(root->left) - high_tree(root->right);
}
// 左旋转
TreeNode* left_rotate(TreeNode* x)
{
TreeNode* y = x->right;
TreeNode* t2 = y->left;
y->left = x;
x->right = t2;
return y;
}
// 右旋转
TreeNode* right_rotate(TreeNode* x)
{
TreeNode* y = x->left;
TreeNode* t2 = y->right;
y->right = x;
x->left = t2;
return y;
}
// 自动调整平衡
TreeNode* auto_balance(TreeNode* x)
{
if(NULL == x) return NULL;
int lh = high_tree(x->left);
int rh = high_tree(x->right);
if(lh-rh > 1)
{
if(diff_high(x->left) >= 1)
{
// 情况1 右旋
x = right_rotate(x);
}
else
{
// 情况3 先左旋 再右旋
x->left = left_rotate(x->left);
x = right_rotate(x);
}
}
else if(rh-lh > 1)
{
if(diff_high(x->right) >= 1)
{
// 情况4 先右旋 再左旋
x->right = right_rotate(x->right);
x = left_rotate(x);
}
else
{
// 情况2 左旋
x = left_rotate(x);
}
}
return x;
}
//添加 有序且平衡 返回root 可能会变化也可能不变 优点不用传二级指针
TreeNode* insert_tree(TreeNode* root,int data)
{
// 按有序添加节点
if(NULL == root)
return create_node(data);
if(root->data > data)
root->left = insert_tree(root->left,data);
else
root->right = insert_tree(root->right,data);
// 自动调成平衡
root = auto_balance(root);
return root;
}
// 前
void dlr_show(TreeNode* root)
{
if(NULL == root) return;
printf("%d ",root->data);
dlr_show(root->left);
dlr_show(root->right);
}
// 中序
void ldr_show(TreeNode* root)
{
if(NULL == root) return;
ldr_show(root->left);
printf("%d ",root->data);
ldr_show(root->right);
}
/*
删除节点:
1、待删除的是叶子节点,直接删除,重新调整
2、待删除的节点度为1,使用非空子树替换,重新调整
3、待删除的节点度为2,根据左右子树高度,选择高的分支,如果左子树高选择最大节点,如果右子树高选择最小节点替换,重新调整
*/
TreeNode* max_tree_node(TreeNode* root)
{
if(NULL == root) return NULL;
TreeNode* max = root;
while(max->right) max = max->right;
return max;
}
TreeNode* min_tree_node(TreeNode* root)
{
if(NULL == root) return NULL;
TreeNode* min = root;
while(min->left) min = min->left;
return min;
}
TreeNode* del_tree(TreeNode* root,int data)
{
if(NULL == root) return NULL;
if(data == root->data)
{
if(NULL == root->left && NULL == root->right)
{
free(root);
return NULL;
}
if(NULL == root->left)
{
// 左空 替换成右
TreeNode* temp = root->right;
free(root);
return temp;
}
if(NULL == root->right)
{
// 右空 替换成左
TreeNode* temp = root->left;
free(root);
return temp;
}
// 左右非空
int lh = high_tree(root->left);
int rh = high_tree(root->right);
if(lh >= rh)
{
// 找左子树最大节点替换
TreeNode* max_node = max_tree_node(root->left);
root->data = max_node->data;
root->left = del_tree(root->left,root->data);
}
else
{
// 找右子树最小节点替换
TreeNode* min_node = min_tree_node(root->right);
root->data = min_node->data;
root->right = del_tree(root->right,root->data);
}
return root;
}
if(data < root->data)
root->left = del_tree(root->left,data);
else
root->right = del_tree(root->right,data);
root = auto_balance(root);
return root;
}
int main(int argc,const char* argv[])
{
TreeNode* root = NULL;
for(int i=0; i<10; i++)
{
root = insert_tree(root,i+1);
}
root = del_tree(root,4);
root = del_tree(root,5);
root = del_tree(root,6);
dlr_show(root);
printf("\n");
ldr_show(root);
}