线索二叉树、选择树和堆

线索二叉树:
链式二叉树中有很多空指针,可以让这些指针指向它的下一个节点(前中后),这样在遍历树时可以不用递归而是使用循环,可以提高树的遍历速度。
中序线过树点数据项:
数:
左子树
右子树
右子树指针标志:(真表示指向的是右子树,假表示指向的是下一个节点)
选择树(了解):
是一种完全二叉树,带比较的数据存储在最后一层,根节点是左右子树的其中一个,是他们的最大的或最小的,能快速找出最大值或最小值

堆:是一种完全二叉树,不适合链式存储。
大根堆:根节点比左右子树大
小根堆:根节点比左右子树小
特点:最顶层是最大值或最小值
数据项:
存储数据的内存首地址
容量
数量
运算:
创建
调整
插入
删除
空或满
堆可以实行优先排序的效果

关于线索二叉树的代码:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>

typedef struct TreeNode
{
	int data;
	struct TreeNode* left;
	struct TreeNode* right;
	bool rclue;				//定义标记线索
}TreeNode;

TreeNode* create_node(int data)
{
	TreeNode* node = malloc(sizeof(TreeNode));
	node->data = data;
	node->left = NULL;
	node->right = NULL;
	node->rclue = false;//线索初始化为false;
	return node;
}

void _insert_tree(TreeNode** root,TreeNode* node)
{
	if(NULL == *root)
	{
		*root = node;
		return;
	}
	if(node->data < (*root)->data)
		_insert_tree(&(*root)->left,node);
	else
		_insert_tree(&(*root)->right,node);

}
void insert_tree(TreeNode** root,int data)//插入
{
	_insert_tree(root,create_node(data));
}

void ldr_show(TreeNode* root)//中序遍历
{
	if(NULL == root) return;
	ldr_show(root->left);
	printf("%d ",root->data);
	ldr_show(root->right);
}

TreeNode* prev = NULL;
void create_clue(TreeNode* root)
{
	if(NULL == root) return;
	create_clue(root->left);
	/*
	if(NULL == root->left)//判断左子树是否还有值
	{
		root->left = prev;//树指向上一个
		root->lclue = true;//标记生效
	}
	*/

	if(NULL!=prev && NULL==prev->right)
	{
		prev->rclue = true;
		prev->right = root;
	}
	prev = root;
	create_clue(root->right);

}

void clue_show(TreeNode* node)
{
	while(node)
	{
		while(node->left)
			node = node->left;
		printf("%d ",node->data);
		while(node->rclue)
		{
			node = node->right;
			printf("%d ",node->data);
		}
		node = node->right;
	}
	printf("\n");
}

int main(int argc,const char* argv[])
{
	TreeNode* root = NULL;
	for(int i = 0; i<10; i++)
	{
		int data = rand() % 100;
		printf("%d ",data);
		insert_tree(&root,data);
	}
	printf("\n");
	ldr_show(root);
	printf("-----------------\n");
	create_clue(root);
	clue_show(root);

}

关于堆的代码:

#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;
	int cal;
	int cnt;
}Heap;

// 创建堆
Heap* create_heap(int cal)
{
	// 申请堆结构需要内存
	Heap* heap = malloc(sizeof(Heap));
	// 申请存储节点需要的内存,由计算双亲、左右子时需要从1开始,因此第一个位置不使用
	heap->arr = malloc(sizeof(TYPE)*cal+1);
	heap->cal = cal;
	// 先加+1再使用
	heap->cnt = 0;
	return heap;
}

// 销毁堆
void destory_heap(Heap* heap)
{
	// 释放存储节点的内存
	free(heap->arr);
	// 释放堆结构的内存
	free(heap);
}

// 堆空
bool empty_heap(Heap* heap)
{
	return !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 i = heap->cnt;
	while(i > 1)
	{
		if(heap->arr[i/2] < heap->arr[i])
		{
			swap(heap->arr[i/2],heap->arr[i]);
		}
		i /= 2;
	}
	
	printf("%d\n",heap->arr[1]);

}

// 删除
bool del_heap(Heap* heap)
{
	if(empty_heap(heap)) return false;
	// 把堆顶与最后一个节点交换
	swap(heap->arr[1],heap->arr[heap->cnt]);
	// 数量减1,就相当于删除的堆
	heap->cnt--;

	// 从上往下进行调整
	int i=1;
	while(i <= heap->cnt)
	{
		// 保证有右子树,把左右子树中较大到交换到左子树中
		if(i*2+1 <= heap->cnt && heap->arr[i*2] < heap->arr[i*2+1])
		{
			swap(heap->arr[i*2],heap->arr[i*2+1]);
		}
		// 保证有左子树,把左子树与根中较大的交换到根中
		if(i*2 <= heap->cnt && heap->arr[i] < heap->arr[i*2])
		{
			swap(heap->arr[i*2],heap->arr[i]);
			i *= 2; 
		}
		else
		{
			// 没有左右子树超出范围
			// 根比左右子树都要大,已经调整到合适位置
			break;
		}
	}

}
// 遍历
void show_heap(Heap* heap)
{
	for(int i=1; i<=heap->cal; i++)
	{
		printf("%d ",heap->arr[i]);
	}
	printf("\n");
}

int main(int argc,const char* argv[])
{
	Heap* heap = create_heap(10);
	for(int i=0; i<10; i++)
	{
		int data = rand() % 100;
		add_heap(heap,data);
	}
	do{
		show_heap(heap);
	}while(del_heap(heap));
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值