赞
踩
#include<GUIQU.h>
int main {
上期回顾: 【数据结构|C语言版】栈和队列
个人主页:C_GUIQU
归属专栏:【数据结构(C语言版)学习】
return 一键三连;
}
各位小伙伴大家好!上次小编给大家讲解了数据结构中的栈和队列,接下来我们讲解一下树、二叉树和堆!
树(Tree)是一种抽象数据类型(ADT),用于模拟具有层次关系的数据集合。在树形结构中,数据以节点(Node)的形式存储,并且每个节点都可以有零个或多个子节点。以下是树相关的基本概念:
树的数据结构可以用多种方式表示。以下是一些常见的树表示方法:
struct TreeNode {
int data;
struct TreeNode *left;
struct TreeNode *right;
};
2*i
的位置,右子节点位于2*i + 1
的位置,其中i
是节点在数组中的索引。struct TreeNode {
int data;
struct TreeNode *firstChild;
struct TreeNode *nextSibling;
};
(A(B,C))
,其中A
是根节点,B
和C
是子节点。树在实际应用中非常广泛,它们以各种形式出现在计算机科学和日常生活的许多领域。以下是一些树的实际应用示例:
#include <stdio.h> #include <stdlib.h> // 定义树节点的结构体 struct TreeNode { int data; struct TreeNode *left; struct TreeNode *right; }; // 创建新节点的函数 struct TreeNode* createNode(int data) { struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode)); if (newNode == NULL) { printf("内存分配失败\n"); exit(EXIT_FAILURE); } newNode->data = data; newNode->left = NULL; newNode->right = NULL; return newNode; } // 插入节点的函数 struct TreeNode* insertNode(struct TreeNode* root, int data) { if (root == NULL) { return createNode(data); } if (data < root->data) { root->left = insertNode(root->left, data); } else if (data > root->data) { root->right = insertNode(root->right, data); } return root; } // 查找节点的函数 struct TreeNode* findNode(struct TreeNode* root, int data) { if (root == NULL || root->data == data) { return root; } if (data < root->data) { return findNode(root->left, data); } else { return findNode(root->right, data); } } // 删除节点的辅助函数,找到最小值节点 struct TreeNode* findMinNode(struct TreeNode* node) { struct TreeNode* current = node; while (current && current->left != NULL) { current = current->left; } return current; } // 删除节点的函数 struct TreeNode* deleteNode(struct TreeNode* root, int data) { if (root == NULL) { return root; } if (data < root->data) { root->left = deleteNode(root->left, data); } else if (data > root->data) { root->right = deleteNode(root->right, data); } else { // 节点找到,进行删除 if (root->left == NULL) { struct TreeNode* temp = root->right; free(root); return temp; } else if (root->right == NULL) { struct TreeNode* temp = root->left; free(root); return temp; } // 节点有两个子节点 struct TreeNode* temp = findMinNode(root->right); root->data = temp->data; root->right = deleteNode(root->right, temp->data); } return root; } // 前序遍历的函数 void preorderTraversal(struct TreeNode* node) { if (node == NULL) { return; } printf("%d ", node->data); preorderTraversal(node->left); preorderTraversal(node->right); } // 中序遍历的函数 void inorderTraversal(struct TreeNode* node) { if (node == NULL) { return; } inorderTraversal(node->left); printf("%d ", node->data); inorderTraversal(node->right); } // 后序遍历的函数 void postorderTraversal(struct TreeNode* node) { if (node == NULL) { return; } postorderTraversal(node->left); postorderTraversal(node->right); printf("%d ", node->data); } // 清理树的函数 void deleteTree(struct TreeNode* root) { if (root == NULL) { return; } deleteTree(root->left); deleteTree(root->right); free(root); } int main() { struct TreeNode* root = NULL; root = insertNode(root, 50); insertNode(root, 30); insertNode(root, 20); insertNode(root, 40); insertNode(root, 70); insertNode(root, 60); insertNode(root, 80); printf("前序遍历: "); preorderTraversal(root); printf("\n"); printf("中序遍历: "); inorderTraversal(root); printf("\n"); printf("后序遍历: "); postorderTraversal(root); printf("\n"); struct TreeNode* node = findNode(root, 60); if (node != NULL) { printf("找到节点: %d\n", node->data); } else { printf("节点未找到\n"); } root = deleteNode(root, 20); printf("删除节点 20 后的中序遍历: "); inorder
二叉树是一种特殊的树形数据结构,每个节点最多有两个子节点,通常称为左子节点和右子节点。
以下是二叉树的一些基本概念和结构:
struct TreeNode {
int data; // 节点存储的数据
struct TreeNode *left; // 指向左子节点的指针
struct TreeNode *right; // 指向右子节点的指针
};
通过这种方式,可以构建和操作各种类型的二叉树,如二叉搜索树、平衡树等。二叉树在计算机科学中非常重要,因为它们提供了一种高效的方式来组织和访问数据。例如,二叉搜索树可以快速地插入、删除和查找数据,而平衡二叉树如AVL树和红黑树则保证了这些操作的最坏情况时间复杂度为O(log n)。
这些性质使得二叉树在数据结构中非常有用,因为它们提供了一种高效的方式来组织和访问数据。
二叉树的存储结构通常指的是如何将二叉树的数据以某种形式存储在计算机的内存中。
常见的二叉树存储结构有顺序存储结构和链式存储结构。
顺序存储结构的优势在于随机访问节点的效率较高,但是插入和删除操作可能需要移动大量节点,导致效率较低。链式存储结构则相反,插入和删除操作的效率较高,但是随机访问节点的效率较低。
在实际应用中,选择哪种存储结构取决于具体的应用场景和对性能的要求。例如,对于需要频繁插入和删除操作的应用,链式存储结构可能更加合适;而对于需要频繁随机访问节点的应用,顺序存储结构可能更加合适。
以下是一个简单的C语言程序,实现了二叉树的创建、插入、查找、删除和遍历操作:
#include <stdio.h> #include <stdlib.h> // 定义二叉树节点的结构体 struct TreeNode { int data; struct TreeNode *left; struct TreeNode *right; }; // 创建新节点的函数 struct TreeNode* createNode(int data) { struct TreeNode* newNode = (struct TreeNode*)malloc(sizeof(struct TreeNode)); if (newNode == NULL) { printf("内存分配失败\n"); exit(EXIT_FAILURE); } newNode->data = data; newNode->left = NULL; newNode->right = NULL; return newNode; } // 插入节点的函数 struct TreeNode* insertNode(struct TreeNode* root, int data) { if (root == NULL) { return createNode(data); } if (data < root->data) { root->left = insertNode(root->left, data); } else if (data > root->data) { root->right = insertNode(root->right, data); } return root; } // 查找节点的函数 struct TreeNode* findNode(struct TreeNode* root, int data) { if (root == NULL || root->data == data) { return root; } if (data < root->data) { return findNode(root->left, data); } else { return findNode(root->right, data); } } // 删除节点的函数 struct TreeNode* deleteNode(struct TreeNode* root, int data) { if (root == NULL) { return root; } if (data < root->data) { root->left = deleteNode(root->left, data); } else if (data > root->data) { root->right = deleteNode(root->right, data); } else { // 节点找到,进行删除 if (root->left == NULL) { struct TreeNode* temp = root->right; free(root); return temp; } else if (root->right == NULL) { struct TreeNode* temp = root->left; free(root); return temp; } // 节点有两个子节点 struct TreeNode* temp = findMinNode(root->right); root->data = temp->data; root->right = deleteNode(root->right, temp->data); } return root; } // 找到最小值节点的辅助函数 struct TreeNode* findMinNode(struct TreeNode* node) { struct TreeNode* current = node; while (current && current->left != NULL) { current = current->left; } return current; } // 前序遍历的函数 void preorderTraversal(struct TreeNode* node) { if (node == NULL) { return; } printf("%d ", node->data); preorderTraversal(node->left); preorderTraversal(node->right); } // 中序遍历的函数 void inorderTraversal(struct TreeNode* node) { if (node == NULL) { return; } inorderTraversal(node->left); printf("%d ", node->data); inorderTraversal(node->right); } // 后序遍历的函数 void postorderTraversal(struct TreeNode* node) { if (node == NULL) { return; } postorderTraversal(node->left); postorderTraversal(node->right); printf("%d ", node->data); } // 清理树的函数 void deleteTree(struct TreeNode* root) { if (root == NULL) { return; } deleteTree(root->left); deleteTree(root->right); free(root); } int main() { struct TreeNode* root = NULL; }
堆(Heap)是一种特别的完全二叉树,它满足两个特性:
堆通常用于实现优先队列(Priority Queue),因为可以在对数时间复杂度内找到最大或最小元素,并且可以在对数时间复杂度内删除或插入元素。
堆通常使用数组来实现。对于数组中的任意位置 i 的元素,其:
堆的主要操作包括:
下面是一个使用 C 语言实现的最大堆的简单示例:
#include <stdio.h> #include <stdlib.h> void swap(int *a, int *b) { int temp = *a; *a = *b; *b = temp; } void heapify(int arr[], int n, int i) { int largest = i; // Initialize largest as root int left = 2 * i + 1; // left = 2*i + 1 int right = 2 * i + 2; // right = 2*i + 2 // If left child is larger than root if (left < n && arr[left] > arr[largest]) largest = left; // If right child is larger than largest so far if (right < n && arr[right] > arr[largest]) largest = right; // If largest is not root if (largest != i) { swap(&arr[i], &arr[largest]); // Recursively heapify the affected sub-tree heapify(arr, n, largest); } } // Main function to do heap sort void heapSort(int arr[], int n) { // Build heap (rearrange array) for (int i = n / 2 - 1; i >= 0; i--) heapify(arr, n, i); // One by one extract an element from heap for (int i = n - 1; i >= 0; i--) { // Move current root to end swap(&arr[0], &arr[i]); // call max heapify on the reduced heap heapify(arr, i, 0); } } // A utility function to print array of size n void printArray(int arr[], int n) { for (int i = 0; i < n; ++i) printf("%d ", arr[i]); printf("\n"); } // Driver program int main() { int arr[] = {12, 11, 13, 5, 6, 7}; int n = sizeof(arr) / sizeof(arr[0]); heapSort(arr, n); printf("Sorted array is \n"); printArray(arr, n); }
在这个示例中,heapify
函数用于维护堆的性质,heapSort
函数用于对数组进行堆排序。堆排序是一种不稳定的比较排序算法,其时间复杂度为 O(n log n)。
在 C 语言中实现二叉树的顺序结构,我们通常使用数组来表示树。下面是一个简单的 C 语言实现,它创建了一个二叉树,并提供了插入、查找和显示节点的功能。
#include <stdio.h> #include <stdlib.h> #define MAX_SIZE 100 // 定义数组的最大容量 // 定义二叉树结构 typedef struct { int data[MAX_SIZE]; // 存储节点的数组 int size; // 树的大小 } BinaryTree; // 初始化二叉树 void initBinaryTree(BinaryTree *tree) { tree->size = 0; // 初始时树的大小为0 } // 判断二叉树是否为空 int isEmpty(BinaryTree *tree) { return tree->size == 0; } // 在二叉树中插入节点 void insert(BinaryTree *tree, int value, int position) { if (position < 1 || position > MAX_SIZE) { printf("位置无效\n"); return; } if (tree->size >= MAX_SIZE) { printf("树已满\n"); return; } tree->size++; // 增加树的大小 tree->data[position] = value; // 在指定位置插入值 } // 获取左子节点 int leftChild(BinaryTree *tree, int position) { int leftPosition = 2 * position; if (leftPosition <= tree->size) { return tree->data[leftPosition]; } else { return -1; // 表示没有左子节点 } } // 获取右子节点 int rightChild(BinaryTree *tree, int position) { int rightPosition = 2 * position + 1; if (rightPosition <= tree->size) { return tree->data[rightPosition]; } else { return -1; // 表示没有右子节点 } } // 获取父节点 int parent(BinaryTree *tree, int position) { if (position > 1) { return tree->data[position / 2]; } else { return -1; // 表示没有父节点 } } // 显示二叉树 void display(BinaryTree *tree) { for (int i = 1; i <= tree->size; i++) { printf("节点位置 %d: 值 %d, 左子节点 %d, 右子节点 %d\n", i, tree->data[i], leftChild(tree, i), rightChild(tree, i)); } } int main() { BinaryTree tree; initBinaryTree(&tree); insert(&tree, 1, 1); insert(&tree, 2, 2); insert(&tree, 3, 3); insert(&tree, 4, 4); insert(&tree, 5, 5); display(&tree); return 0; }
在这个实现中,我们定义了一个 BinaryTree
结构,其中包含一个整数数组 data
来存储树的节点,以及一个整数 size
来表示树的大小。我们提供了初始化、插入、查找和显示树的方法。这个实现假设树是一个完全二叉树,因此它适用于完全二叉树或近似完全二叉树的情况。如果树不是完全二叉树,那么数组表示法可能会导致空间浪费。
二叉树的链式结构实现通常使用节点(Node)和指针(在 C 语言中是指针,在其他语言中可能是引用或其他形式的间接访问)。每个节点包含一个数据字段和两个指针字段,分别指向其左子节点和右子节点。如果某个节点没有子节点,则相应的指针字段为 NULL。
以下是一个使用 C 语言实现的二叉树链式结构的基本操作:
#include <stdio.h> #include <stdlib.h> // 定义二叉树节点的结构 typedef struct TreeNode { int data; // 节点存储的数据 struct TreeNode *left; // 指向左子节点的指针 struct TreeNode *right; // 指向右子节点的指针 } TreeNode; // 创建新节点 TreeNode* createNode(int value) { TreeNode *newNode = (TreeNode*)malloc(sizeof(TreeNode)); if (!newNode) { return NULL; } newNode->data = value; newNode->left = newNode->right = NULL; return newNode; } // 向二叉树中插入节点 void insertNode(TreeNode **root, int value) { if (*root == NULL) { *root = createNode(value); } else { TreeNode *current = *root; TreeNode *parent = NULL; while (current != NULL) { parent = current; if (value < current->data) { current = current->left; } else { current = current->right; } } if (value < parent->data) { parent->left = createNode(value); } else { parent->right = createNode(value); } } } // 中序遍历二叉树 void inorderTraversal(TreeNode *root) { if (root != NULL) { inorderTraversal(root->left); printf("%d ", root->data); inorderTraversal(root->right); } } // 主函数 int main() { TreeNode *root = NULL; // 插入节点 insertNode(&root, 50); insertNode(&root, 30); insertNode(&root, 20); insertNode(&root, 40); insertNode(&root, 70); insertNode(&root, 60); insertNode(&root, 80); // 中序遍历二叉树 printf("中序遍历二叉树: "); inorderTraversal(root); printf("\n"); return 0; }
在这个实现中,我们定义了一个 TreeNode
结构,它包含一个整数值 data
和两个指向 TreeNode
的指针 left
和 right
。createNode
函数用于创建一个新的节点,insertNode
函数用于向树中插入一个新的节点,inorderTraversal
函数用于中序遍历树并打印节点的值。
这个基本的实现没有包含删除节点的功能,也没有进行任何形式的平衡或优化。在实际应用中,我们可能需要根据具体需求添加更多的功能,比如平衡二叉树(如 AVL 树或红黑树)、查找节点、删除节点等。
以上就是小编对树、二叉树和堆的讲解。
如果觉得小编讲的还可以,还请一键三连。互三必回!
持续更新中~!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。