数据结构~树

目录

二叉树基本概念:

 先序流程:

中序流程:

后序流程:

二叉树:节点和边上的数学特性

大顶堆:


二叉树基本概念:

分类:

1.空的二叉树:就结构体指针 tree=NULL

2.只有根节点的二叉树 (只有一个结点)

3.只有左子树或者右子树的二叉树

4.左右子树都存在:完全二叉树,满二叉树(编号是按顺序的)

注:红色的点是父节点,绿色的是孩节点(孩节点/2=父节点)

代码:

别名:LPSTR:char*                 LPCSTR: const char*   (定义别名用LP表示指针)


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

typedef struct treeNode
{
	char data;//数据域用字符表示
	struct treeNode* LCHild;
	struct treeNode* RCHild;
}TREE,*LPTREE;

LPTREE createNode(char data)
{
	LPTREE newNode = (LPTREE)malloc(sizeof(TREE));
	if (!newNode)
	{
		printf("创建新节点失败!");
		exit(0);
	}
	else
	{
		newNode->data = data;
		newNode->LCHild = NULL;
		newNode->RCHild = NULL;
		return newNode;
	}
}
//没有规律的树
void insertNode(LPTREE parentNode, LPTREE LCHild, LPTREE RCHild)
{
	parentNode->LCHild = LCHild;
	parentNode->RCHild = RCHild;
}
//打印当前节点中的元素
void print(LPTREE curData)
{
	printf("%c   ", curData->data);
}
//递归,前序
void preOrder(LPTREE root)
{
	if (root != NULL)
	{
		print(root);//根
		preOrder(root->LCHild);//左
		preOrder(root->RCHild);//右
	}
}
//中序
//递归
void preOrder2(LPTREE root)
{
	if (root != NULL)
	{
		preOrder2(root->LCHild);//左
		print(root);//根
		preOrder2(root->RCHild);//右

	}
}
//后序
//递归
void preOrder3(LPTREE root)
{
	if (root != NULL)
	{
		preOrder3(root->LCHild);//左
		preOrder3(root->RCHild);//右
		print(root);//根
	}
}
int main()
{
	//死板的创建过程,无实际作用
	LPTREE A = createNode('A');
	LPTREE B = createNode('B');
	LPTREE C = createNode('C');
	LPTREE D = createNode('D');
	LPTREE E = createNode('E');
	LPTREE F = createNode('F');
	LPTREE G = createNode('G');
	insertNode(A, B, C);
	insertNode(B, D, NULL);
	insertNode(D, NULL, G);
	insertNode(C, E, F);
	printf("先序:");
	preOrder(A);
	printf("\n中序:");
	preOrder2(A);
	printf("\n后序:");
	preOrder3(A);




	return 0;
}

 先序流程:

 先序代码

void preOderBystack(LPTREE root)
{
	if (root == NULL)
		return;
	//准备入栈
	struct treeNode* stack[10];//存储每次打印节点的位置
	int stackTop = -1;//栈顶标记
	LPTREE pMove = root;//从根节点开始打印
	while (stackTop != -1 || pMove)
	{
		while (pMove)
		{
			//把路径入栈+打印走过的节点
			printf("%c ", pMove->data);
			stack[++stackTop] = pMove;
			pMove = pMove->LCHild;
		}
		//无路可走
		if (stackTop != -1)
		{
			pMove = stack[stackTop];//获取栈顶元素
			stackTop--;//出栈
			pMove = pMove->RCHild;
		}	
	}
}

中序流程:

 中序代码:

//中序
void preOderBystack2(LPTREE root)
{
	if (root == NULL)
		return;
	struct treeNode* stack[10];
	int stackTop = -1;
	LPTREE pMove = root;
	while (stackTop != -1 || pMove)
	{
		while (pMove)
		{
			stack[++stackTop] = pMove;
			pMove = pMove->LCHild;
		}
		//出栈
		if (stackTop != -1)
		{
			pMove = stack[stackTop--];
			printf("%c ", pMove->data);
			pMove = pMove->RCHild;
		}
	}
}

后序流程:

void preOderBystack3(LPTREE root)
{
	if (root == NULL)
		return;
	struct treeNode* stack[10];
	int stackTop = -1;
	struct treeNode* pMove = root;
	struct treeNode* plastVisit = NULL;//访问标记
	//左 右 根
    //pMove一直来到最左下角
	while (pMove)
	{
		stack[++stackTop] = pMove;
		pMove = pMove->LCHild;
	}
//开始出栈,判断右边是否有节点是否被访问过
	while (stackTop != -1)
	{
		pMove = stack[stackTop--];
		//当前节点左右是否被访问
		if (pMove->RCHild == NULL || pMove->RCHild == plastVisit)
		{
			//如果被访问就可以打印当前节点数据
			printf("%c ", pMove->data);
			plastVisit = pMove;//改变标记位置
		}
		else
		{
			//右边没有被访问
			stack[++stackTop] = pMove;
			pMove = pMove->RCHild;
			while (pMove)
			{
				stack[++stackTop] = pMove;
				pMove = pMove->LCHild;
			}
		}
	}
}

int main()
{
	//死板的创建过程,无实际作用
	LPTREE A = createNode('A');
	LPTREE B = createNode('B');
	LPTREE C = createNode('C');
	LPTREE D = createNode('D');
	LPTREE E = createNode('E');
	LPTREE F = createNode('F');
	LPTREE G = createNode('G');
	insertNode(A, B, C);
	insertNode(B, D, E);
	insertNode(C, F, G);
	printf("先序:");
	preOderBystack(A);
	printf("\n中序:");
	preOderBystack2(A);
	printf("\n后序:");
	preOderBystack3(A);
	

二叉树:节点和边上的数学特性

深度:几层

1.第i层最多有2^(i-1)个节点

2.二叉树深度是i,最多有多少个节点:2^i-1

3.假设二叉树有n个节点,二叉树最小深度是:log₂(n+1)

大顶堆:

 大顶堆入堆过程:


#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 10

typedef struct Heap
{
	int sizeHeap;
	int* heapData;
}HEAP,*LPHEAP;
//创建堆
LPHEAP createHeap()
{
	LPHEAP heap = (LPHEAP)malloc(sizeof(HEAP));
	heap->sizeHeap = 0;
	heap->heapData = (int*)malloc(sizeof(int) * MAX);
	return heap;
}
//万金油
int size(LPHEAP heap)
{
	return heap->sizeHeap;
}
int empty(LPHEAP heap)
{
	//返回1 表示NULL 返回0 表示不为NULL
	return heap->sizeHeap == 0;
}
void moveTocrrectPos(LPHEAP heap, int curPos)
{
	//向上渗透
	while (curPos > 1)//渗透到下标是1的位置,表示结束
	{
		int Max = heap->heapData[curPos];//比较
		int parentIndex = curPos / 2;
		if (Max > heap->heapData[parentIndex])
		{
			//交换孩子点和父节点的值
			heap->heapData[curPos] = heap->heapData[parentIndex];
			heap->heapData[parentIndex] = Max;
			curPos = parentIndex;
		}
		else
			break;//不需要调整
	}
}

//入堆
void insertHeap(LPHEAP heap, int data)
{
	//放到当前堆的最后面
	++heap->sizeHeap;
	heap->heapData[heap->sizeHeap] = data;
	//大顶堆,调整当前元素的位置
	moveTocrrectPos(heap, heap->sizeHeap);
}

int main()
{
	LPHEAP heap = createHeap();
	//数组下标[0]那段内存不会去用!!!!
	for (int i = 1; i < 11; i++)
	{
		insertHeap(heap, i);
	}
	for (int i = 1; i < 11; i++)
	{
		printf("%d  ", heap->heapData[i]);
	}
	printf("\n");

	return 0;
}

出堆过程:

int popHeap(LPHEAP heap)
{
	int Max = heap->heapData[1];
	//调整堆,向下渗透,找最后一个适合的位置的下标
	int curPos = 1;
	int childIndex = curPos * 2;
	while (childIndex <= heap->sizeHeap)
	{
		int temp = heap->heapData[childIndex];
		//同一层上面需要左右比较
		if (childIndex + 1 <= heap->sizeHeap && temp < heap->heapData[childIndex + 1])
		{
			temp = heap->heapData[++childIndex];//等效于childIndex+1
		}
		heap->heapData[curPos] = temp;
		curPos = childIndex;
		childIndex*= 2;
	}
	heap->heapData[curPos] = heap->heapData[heap->sizeHeap];
	--heap->sizeHeap;
	return Max;
}
while (!empty(heap))
	{
		printf("%d ", popHeap(heap));
	}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Luckys-Yang

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值