数据结构 二叉树与哈希表

一、二叉树部分

1. 基础概念
  • 树结构:一种描述 "一对多" 关系的数据结构,由节点和边构成。
  • 节点分类
    • 根节点:树的起始节点,只有后继,没有前驱。
    • 分支节点:既有前驱又有后继,一个树中分支节点最多有一个前驱,但可以有多个后继。
    • 叶子节点:只有前驱,没有后继,是树的末端节点。
  • 核心术语
    • :节点的前驱或后继的个数。入度(指向该节点的边数)均为 1,出度(该节点指向其他节点的边数)为后继节点的个数。
    • :根节点在第 1 层,每向下一层,层数 + 1。
    • 高度:该节点到其最远叶子节点的距离。
    • 深度:该节点到根节点的节点个数。
    • 树的高度:等于树的最大层数,也等于根节点的深度。
2. 二叉树定义与特性
  • 定义:每个节点最多有 2 个后继节点(左孩子、右孩子)的树形结构。
  • 特殊二叉树
    • 满二叉树:所有叶子节点都在同一层,且每个非叶子节点都有两个子节点。
    • 完全二叉树:将二叉树所有节点按层序编号后,编号连续且与满二叉树的编号顺序完全对应。
  • 关键特性
    • 第 k 层最多有 2(k−1) 个节点。
    • 前 k 层最多有 2k−1 个节点。
3. 二叉树的遍历
  • 深度优先遍历(DFS)
    1. 前序遍历:根 → 左 → 右
    2. 中序遍历:左 → 根 → 右
    3. 后序遍历:左 → 右 → 根
  • 广度优先遍历(BFS)
    1. 层序遍历 :按节点所在的层,从上到下、从左到右依次访问。

      cpp 复制代码
      #include "btree.h"
      #include <stdio.h>
      #include <stdlib.h>
      #include "linkqueue.h"
      #include "seqstack.h"
      
      TreeNode_t *CreateCompleteBTree(int StartNo, int EndNo)
      {
      	TreeNode_t *pNewNode = NULL;
      
      	if (StartNo > EndNo)
      	{
      		return NULL;
      	}
      	
      	pNewNode = malloc(sizeof(TreeNode_t));
      	if (NULL == pNewNode)
      	{
      		perror("fail to malloc");
      		return NULL;
      	}
      
      	pNewNode->No = StartNo;
      	pNewNode->pLeftChild = CreateCompleteBTree(2*StartNo, EndNo);
      	pNewNode->pRightChild = CreateCompleteBTree(2*StartNo+1, EndNo);
      
      	return pNewNode;
      }
      
      void PreOrderBTree(TreeNode_t *pTmpRoot)
      {
      	printf("%d(%c) ", pTmpRoot->No, pTmpRoot->Data);
      	if (pTmpRoot->pLeftChild != NULL)
      		PreOrderBTree(pTmpRoot->pLeftChild);
      	if (pTmpRoot->pRightChild != NULL)
      		PreOrderBTree(pTmpRoot->pRightChild);
      
      	return;
      }
      
      void InOrderBTree(TreeNode_t *pTmpRoot)
      {
      	if (pTmpRoot->pLeftChild != NULL)
      		InOrderBTree(pTmpRoot->pLeftChild);
      	printf("%d(%c) ", pTmpRoot->No, pTmpRoot->Data);
      	if (pTmpRoot->pRightChild != NULL)
      		InOrderBTree(pTmpRoot->pRightChild);
      
      	return;
      }
      
      void PostOrderBTree(TreeNode_t *pTmpRoot)
      {
      	if (pTmpRoot->pLeftChild != NULL)
      		PostOrderBTree(pTmpRoot->pLeftChild);
      	if (pTmpRoot->pRightChild != NULL)
      		PostOrderBTree(pTmpRoot->pRightChild);
      	printf("%d(%c) ", pTmpRoot->No, pTmpRoot->Data);
      
      	return;
      }
      
      int DestroyBTree(TreeNode_t **ppTmpRoot)
      {
      	if ((*ppTmpRoot)->pLeftChild != NULL)
      		DestroyBTree(&(*ppTmpRoot)->pLeftChild);
      	if ((*ppTmpRoot)->pRightChild != NULL)
      		DestroyBTree(&(*ppTmpRoot)->pRightChild);
      	free(*ppTmpRoot);
      	*ppTmpRoot = NULL;
      
      	return 0;
      }
      
      int LayoutOderBTree(TreeNode_t *pTmpRoot)
      {
      	Node_t *pTmpQueue = NULL;
      	DataType pTmpNode = NULL;
      
      	if (NULL == pTmpRoot)
      	{
      		return 0;
      	}
      
      	pTmpQueue = CreateEmptyLinkQueue();
      	EnterLinkQueue(pTmpQueue, pTmpRoot);
      
      	while (!IsEmptyLinkQueue(pTmpQueue))
      	{
      		pTmpNode = QuitLinkQueue(pTmpQueue);
      		printf("%d(%c) ", pTmpNode->No, pTmpNode->Data);
      
      		if (pTmpNode->pLeftChild != NULL)
      			EnterLinkQueue(pTmpQueue, pTmpNode->pLeftChild);
      		if (pTmpNode->pRightChild != NULL)
      			EnterLinkQueue(pTmpQueue, pTmpNode->pRightChild);
      	}
      
      	DestroyLinkQueue(&pTmpQueue);
      
      	return 0;
      }
      
      int GetBTreeHigh(TreeNode_t *pTmpRoot)
      {
      	int LeftHigh = 0;
      	int RightHigh = 0;
      	
      	if (NULL == pTmpRoot)
      	{
      		return 0;
      	}
      
      	LeftHigh = GetBTreeHigh(pTmpRoot->pLeftChild);
      	RightHigh = GetBTreeHigh(pTmpRoot->pRightChild);
      
      	return (LeftHigh > RightHigh ? LeftHigh : RightHigh) + 1;
      }
      
      TreeNode_t *CreateBTree(int No)
      {
      	TreeNode_t *pNewNode = NULL;
      	char ch = 0;
      	
      	scanf(" %c", &ch);
      	if ('#' == ch)
      	{
      		return NULL;
      	}
      	else 
      	{
      		pNewNode = malloc(sizeof(TreeNode_t));
      		if (NULL == pNewNode)
      		{
      			perror("fail to malloc");
      			return NULL;
      		}	
      	
      		pNewNode->No = No;
      		pNewNode->Data = ch;
      		pNewNode->pLeftChild = CreateBTree(2*No);
      		pNewNode->pRightChild = CreateBTree(2*No+1);
      	}
      
      	return pNewNode;
      }
      
      void PreOrderBTreeByStack(TreeNode_t *pTmpRoot)
      {
      	SeqStack_t *pTmpStack = NULL;
      	TreeNode_t *pTmpNode = NULL;
      
      	pTmpStack = CreateSeqStack(50);
      	pTmpNode = pTmpRoot;
      
      	while (1)
      	{
      		while (pTmpNode != NULL)
      		{
      			printf("%d(%c) ", pTmpNode->No, pTmpNode->Data);
      			PushSeqStack(pTmpStack, pTmpNode);
      			pTmpNode = pTmpNode->pLeftChild;
      		}
      		
      		if (IsEmptySeqStack(pTmpStack))
      		{
      			break;
      		}
      
      		pTmpNode = PopSeqStack(pTmpStack);
      		pTmpNode = pTmpNode->pRightChild;
      	}
      
      	DestroySeqStack(&pTmpStack);
      
      	return;
      }
      
      void InOrderBTreeByStack(TreeNode_t *pTmpRoot)
      {
      	SeqStack_t *pTmpStack = NULL;
      	TreeNode_t *pTmpNode = NULL;
      
      	pTmpStack = CreateSeqStack(50);
      	pTmpNode = pTmpRoot;
      
      	while (1)
      	{
      		while (pTmpNode != NULL)
      		{
      			PushSeqStack(pTmpStack, pTmpNode);
      			pTmpNode = pTmpNode->pLeftChild;
      		}
      		
      		if (IsEmptySeqStack(pTmpStack))
      		{
      			break;
      		}
      
      		pTmpNode = PopSeqStack(pTmpStack);
      		printf("%d(%c) ", pTmpNode->No, pTmpNode->Data);
      		pTmpNode = pTmpNode->pRightChild;
      	}
      
      	DestroySeqStack(&pTmpStack);
      
      	return;
      }
      
      void PostOrderBTreeByStack(TreeNode_t *pTmpRoot)
      {
      	SeqStack_t *pTmpStack = NULL;
      	TreeNode_t *pTmpNode = NULL;
      
      	pTmpStack = CreateSeqStack(50);
      	pTmpNode = pTmpRoot;
      
      	while (1)
      	{
      		while (pTmpNode != NULL)
      		{
      			pTmpNode->Flag = 1;
      			PushSeqStack(pTmpStack, pTmpNode);
      			pTmpNode = pTmpNode->pLeftChild;
      		}
      		
      		if (IsEmptySeqStack(pTmpStack))
      		{
      			break;
      		}
      
      		pTmpNode = PopSeqStack(pTmpStack);
      		if (1 == pTmpNode->Flag)
      		{
      			pTmpNode->Flag = 0;
      			PushSeqStack(pTmpStack, pTmpNode);
      			pTmpNode = pTmpNode->pRightChild;
      		}
      		else if (0 == pTmpNode->Flag)
      		{
      			printf("%d(%c) ", pTmpNode->No, pTmpNode->Data);
      			pTmpNode = NULL;
      		}
      	}
      
      	DestroySeqStack(&pTmpStack);
      
      	return;
      }

二、哈希表部分

1. 核心思想

哈希表是一种通过哈希函数将数据映射为存储地址(键值)的数据结构,目标是实现 O(1) 时间复杂度的增删改查操作。

2. 哈希冲突
  • 定义:多个不同的原始数据,通过哈希函数计算后得到了相同的键值,这种情况称为哈希冲突(哈希冲突)。

  • 解决方法(链地址法):当发生哈希冲突时,在同一个键值对应的存储位置上,用链表来存储多个冲突的数据。

    cpp 复制代码
    #include "hashtable.h"
    #include <stdio.h>
    #include <stdlib.h>
    
    static Node_t *pHashTable[10];
    
    int InsertHashTable(int TmpData)
    {
    	int Index = 0;		
    	Node_t *pNewNode = NULL;
    	Node_t **ppTmpNode = NULL;
    
    	Index = TmpData % 10;
    	for (ppTmpNode = &pHashTable[Index]; *ppTmpNode != NULL && TmpData > (*ppTmpNode)->Data;ppTmpNode = &(*ppTmpNode)->pNext);
    
    	pNewNode = malloc(sizeof(Node_t));
    	if(NULL == pNewNode)
    	{
    		perror("fail to malloc");
    		return -1;
    	}
    
    	pNewNode->Data = TmpData;
    	pNewNode->pNext = *ppTmpNode;
    	*ppTmpNode = pNewNode;
    
    	return 0;
    }
    
    void ShowHashTable(void)
    {
    	int i = 0;
    	Node_t *pTmpNode = NULL;
    
    	for(i = 0; i < 10; i++)
    	{
    		printf("%d:",i);	
    		pTmpNode = pHashTable[i];
    		while(pTmpNode != NULL)
    		{
    			printf("%d ",pTmpNode->Data);
    			pTmpNode = pTmpNode->pNext;
    		}
    		printf("\n");
    	}
    	
    	return;
    }
    
    int FindHashTable(int TmpData)
    {
    	int tmp = 0;
    	Node_t *pTmpNode = NULL;
    	
    	tmp = TmpData % 10;
    	pTmpNode = pHashTable[tmp];
    	while(NULL != pTmpNode)
    	{
    		if(pTmpNode->Data == TmpData)
    		{
    			return 1;
    		}
    		else if(pTmpNode->Data > TmpData)
    		{
    			return 0;
    		}
    		pTmpNode = pTmpNode->pNext;
    	}
    
    	return 0;
    }	
    	
    int DestoryHashTable(void)
    {
    	int i = 0;
    	Node_t *pTmpNode = NULL;
    	Node_t *pFreeNode = NULL;
    
    	for(i = 0; i < 10; i++)
    	{
    		pTmpNode = pFreeNode = pHashTable[i];	
    		while(NULL != pTmpNode)
    		{
    			pTmpNode = pTmpNode->pNext;
    			free(pFreeNode);
    			pFreeNode = pTmpNode;
    		}
    		pHashTable[i] = NULL;
    	}
    
    	return 0;
    }
相关推荐
Sayuanni%32 小时前
数据结构_Map和Set
java·数据结构
执着2593 小时前
力扣hot100 - 144、二叉树的前序遍历
数据结构·算法·leetcode
近津薪荼3 小时前
递归专题(4)——两两交换链表中的节点
数据结构·c++·学习·算法·链表
散峰而望3 小时前
【算法竞赛】树
java·数据结构·c++·算法·leetcode·贪心算法·推荐算法
鱼很腾apoc3 小时前
【实战篇】 第14期 算法竞赛_数据结构超详解(下)
c语言·开发语言·数据结构·学习·算法·青少年编程
近津薪荼3 小时前
递归专题(3)——反转链表
数据结构·c++·学习·算法·链表
senijusene3 小时前
数据结构与算法:完全二叉树和非完全二叉数的各种详细操作以及哈希表的简单应用
数据结构·算法·链表
季明洵4 小时前
反转字符串、反转字符串II、反转字符串中的单词
java·数据结构·算法·leetcode·字符串
Hello World . .4 小时前
数据结构:哈希表(Hash table)
数据结构·vim·哈希算法·散列表