数据结构 二叉树与哈希表

一、二叉树部分

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;
    }
相关推荐
见叶之秋34 分钟前
详解单链表(含链表的实现过程)
数据结构·链表
仟濹1 小时前
【算法打卡day23(2026-03-15 周日)今日算法or技巧:双指针 & 链表 & 回溯算法】6个题
数据结构·算法·链表
Je1lyfish1 小时前
CMU15-445 (2026 Spring) Project#2 - B+ Tree
linux·数据结构·数据库·c++·sql·spring·oracle
沉鱼.441 小时前
序列问题模型(LIS LCS LCIS)
数据结构
无尽的罚坐人生2 小时前
hot 100 35. 搜索插入位置
数据结构·算法·leetcode·二分查找
自信150413057592 小时前
数据结构之实现链式结构二叉树
c语言·数据结构·算法
EE工程师2 小时前
数据结构篇 - C语言如何实现OOP
数据结构·oop
Barkamin2 小时前
堆排序简单实现
java·数据结构·算法·排序算法
迈巴赫车主2 小时前
天梯赛 L2-004 这是二叉搜索树吗?java
java·开发语言·数据结构·算法·天梯赛
沐苏瑶2 小时前
Java 数据结构精讲:二叉树遍历算法与底层实现剖析
数据结构·算法