C语言实现常见的数据结构

news2024/9/28 12:59:52

栈是一种后进先出(LIFO, Last In First Out)的数据结构

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

#define MAX 100

typedef struct {
    int data[MAX];
    int top;
} Stack;

// 初始化栈
void init(Stack *s) {
    s->top = -1;
}

// 判断栈是否为空
int isEmpty(Stack *s) {
    return s->top == -1;
}

// 判断栈是否满
int isFull(Stack *s) {
    return s->top == MAX - 1;
}

// 入栈
void push(Stack *s, int value) {
    if (isFull(s)) {
        printf("Stack overflow!\n");
        return;
    }
    s->data[++s->top] = value;
}

// 出栈
int pop(Stack *s) {
    if (isEmpty(s)) {
        printf("Stack underflow!\n");
        exit(1);
    }
    return s->data[s->top--];
}

// 打印栈
void printStack(Stack *s) {
    for (int i = 0; i <= s->top; i++) {
        printf("%d ", s->data[i]);
    }
    printf("\n");
}

int main() {
    Stack s;
    init(&s);
    push(&s, 10);
    push(&s, 20);
    push(&s, 30);
    printStack(&s);
    pop(&s);
    printStack(&s);
    return 0;
}

队列

队列是一种先进先出(FIFO, First In First Out)的数据结构。

循环队列

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

#define MAX 100

typedef struct {
    int data[MAX];
    int front;
    int rear;
} Queue;

// 初始化队列
void init(Queue *q) {
    q->front = 0;
    q->rear = 0;
}

// 判断队列是否为空
int isEmpty(Queue *q) {
    return q->front == q->rear;
}

// 判断队列是否满
int isFull(Queue *q) {
    return (q->rear + 1) % MAX == q->front;
}

// 入队
void enqueue(Queue *q, int value) {
    if (isFull(q)) {
        printf("Queue overflow!\n");
        return;
    }
    q->data[q->rear] = value;
    q->rear = (q->rear + 1) % MAX;
}

// 出队
int dequeue(Queue *q) {
    if (isEmpty(q)) {
        printf("Queue underflow!\n");
        exit(1);
    }
    int value = q->data[q->front];
    q->front = (q->front + 1) % MAX;
    return value;
}

// 打印队列
void printQueue(Queue *q) {
    for (int i = q->front; i != q->rear; i = (i + 1) % MAX) {
        printf("%d ", q->data[i]);
    }
    printf("\n");
}

int main() {
    Queue q;
    init(&q);
    enqueue(&q, 10);
    enqueue(&q, 20);
    enqueue(&q, 30);
    printQueue(&q);
    dequeue(&q);
    printQueue(&q);
    return 0;
}

平衡二叉树 (AVL Tree)

AVL树是一种自平衡二叉搜索树,任何节点的左右子树高度差不超过1。

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

// 定义节点
typedef struct Node {
    int key;
    struct Node *left;
    struct Node *right;
    int height;
} Node;

// 获取节点的高度
int height(Node *n) {
    if (n == NULL) return 0;
    return n->height;
}

// 创建新节点
Node* newNode(int key) {
    Node* node = (Node*)malloc(sizeof(Node));
    node->key = key;
    node->left = node->right = NULL;
    node->height = 1;
    return node;
}

// 右旋转
Node* rightRotate(Node* y) {
    Node* x = y->left;
    Node* T2 = x->right;
    x->right = y;
    y->left = T2;
    y->height = 1 + fmax(height(y->left), height(y->right));
    x->height = 1 + fmax(height(x->left), height(x->right));
    return x;
}

// 左旋转
Node* leftRotate(Node* x) {
    Node* y = x->right;
    Node* T2 = y->left;
    y->left = x;
    x->right = T2;
    x->height = 1 + fmax(height(x->left), height(x->right));
    y->height = 1 + fmax(height(y->left), height(y->right));
    return y;
}

// 获取平衡因子
int getBalance(Node* n) {
    if (n == NULL) return 0;
    return height(n->left) - height(n->right);
}

// 插入节点
Node* insert(Node* node, int key) {
    if (node == NULL) return newNode(key);
    if (key < node->key)
        node->left = insert(node->left, key);
    else if (key > node->key)
        node->right = insert(node->right, key);
    else
        return node;

    node->height = 1 + fmax(height(node->left), height(node->right));
    int balance = getBalance(node);

    // 平衡调整
    if (balance > 1 && key < node->left->key)
        return rightRotate(node);
    if (balance < -1 && key > node->right->key)
        return leftRotate(node);
    if (balance > 1 && key > node->left->key) {
        node->left = leftRotate(node->left);
        return rightRotate(node);
    }
    if (balance < -1 && key < node->right->key) {
        node->right = rightRotate(node->right);
        return leftRotate(node);
    }
    return node;
}

// 中序遍历
void inorder(Node* root) {
    if (root != NULL) {
        inorder(root->left);
        printf("%d ", root->key);
        inorder(root->right);
    }
}

int main() {
    Node* root = NULL;
    root = insert(root, 10);
    root = insert(root, 20);
    root = insert(root, 30);
    root = insert(root, 40);
    root = insert(root, 50);
    inorder(root);
    return 0;
}

最优二叉树(哈夫曼树)的实现

哈夫曼树是一种用于数据压缩的二叉树。它是一种最优的前缀编码树,使用频率最低的字符分配最长的编码,从而达到压缩的效果。

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

// 定义哈夫曼树的节点
typedef struct Node {
    char data;
    int freq;
    struct Node *left, *right;
} Node;

// 创建一个新的节点
Node* newNode(char data, int freq) {
    Node* node = (Node*)malloc(sizeof(Node));
    node->data = data;
    node->freq = freq;
    node->left = node->right = NULL;
    return node;
}

// 交换两个节点
void swap(Node** a, Node** b) {
    Node* temp = *a;
    *a = *b;
    *b = temp;
}

// 小顶堆 (Min Heap) 结构
typedef struct MinHeap {
    int size;
    int capacity;
    Node** array;
} MinHeap;

// 创建一个小顶堆
MinHeap* createMinHeap(int capacity) {
    MinHeap* minHeap = (MinHeap*)malloc(sizeof(MinHeap));
    minHeap->size = 0;
    minHeap->capacity = capacity;
    minHeap->array = (Node**)malloc(minHeap->capacity * sizeof(Node*));
    return minHeap;
}

// 堆化 (Heapify)
void minHeapify(MinHeap* minHeap, int idx) {
    int smallest = idx;
    int left = 2 * idx + 1;
    int right = 2 * idx + 2;

    if (left < minHeap->size && minHeap->array[left]->freq < minHeap->array[smallest]->freq)
        smallest = left;

    if (right < minHeap->size && minHeap->array[right]->freq < minHeap->array[smallest]->freq)
        smallest = right;

    if (smallest != idx) {
        swap(&minHeap->array[smallest], &minHeap->array[idx]);
        minHeapify(minHeap, smallest);
    }
}

// 提取最小值节点
Node* extractMin(MinHeap* minHeap) {
    Node* temp = minHeap->array[0];
    minHeap->array[0] = minHeap->array[minHeap->size - 1];
    --minHeap->size;
    minHeapify(minHeap, 0);
    return temp;
}

// 插入节点到堆
void insertMinHeap(MinHeap* minHeap, Node* node) {
    ++minHeap->size;
    int i = minHeap->size - 1;

    while (i && node->freq < minHeap->array[(i - 1) / 2]->freq) {
        minHeap->array[i] = minHeap->array[(i - 1) / 2];
        i = (i - 1) / 2;
    }
    minHeap->array[i] = node;
}

// 创建并构建小顶堆
MinHeap* buildMinHeap(char data[], int freq[], int size) {
    MinHeap* minHeap = createMinHeap(size);
    for (int i = 0; i < size; ++i)
        minHeap->array[i] = newNode(data[i], freq[i]);
    minHeap->size = size;
    for (int i = (minHeap->size - 2) / 2; i >= 0; --i)
        minHeapify(minHeap, i);
    return minHeap;
}

// 构建哈夫曼树
Node* buildHuffmanTree(char data[], int freq[], int size) {
    Node *left, *right, *top;
    MinHeap* minHeap = buildMinHeap(data, freq, size);

    while (minHeap->size != 1) {
        left = extractMin(minHeap);
        right = extractMin(minHeap);
        top = newNode('$', left->freq + right->freq);
        top->left = left;
        top->right = right;
        insertMinHeap(minHeap, top);
    }

    return extractMin(minHeap);
}

// 打印哈夫曼编码
void printCodes(Node* root, int arr[], int top) {
    if (root->left) {
        arr[top] = 0;
        printCodes(root->left, arr, top + 1);
    }

    if (root->right) {
        arr[top] = 1;
        printCodes(root->right, arr, top + 1);
    }

    if (!root->left && !root->right) {
        printf("%c: ", root->data);
        for (int i = 0; i < top; ++i)
            printf("%d", arr[i]);
        printf("\n");
    }
}

// 哈夫曼编码主函数
void HuffmanCodes(char data[], int freq[], int size) {
    Node* root = buildHuffmanTree(data, freq, size);
    int arr[100], top = 0;
    printCodes(root, arr, top);
}

int main() {
    char arr[] = { 'a', 'b', 'c', 'd', 'e', 'f' };
    int freq[] = { 5, 9, 12, 13, 16, 45 };
    int size = sizeof(arr) / sizeof(arr[0]);

    HuffmanCodes(arr, freq, size);

    return 0;
}

B树的实现

B树是一种多路自平衡的搜索树,常用于数据库和文件系统。以下是B树的基本实现。

 

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

#define T 3  // B树的最小度数

// 定义B树的节点
typedef struct BTreeNode {
    int keys[2*T-1];     // 存储键
    struct BTreeNode* C[2*T]; // 存储子节点指针
    int n;            // 当前节点存储的键数量
    int leaf;         // 是否为叶子节点
} BTreeNode;

// 创建一个B树节点
BTreeNode* createNode(int leaf) {
    BTreeNode* node = (BTreeNode*)malloc(sizeof(BTreeNode));
    node->leaf = leaf;
    node->n = 0;
    for (int i = 0; i < 2*T; i++) {
        node->C[i] = NULL;
    }
    return node;
}

// 在非满节点插入键
void insertNonFull(BTreeNode* node, int k) {
    int i = node->n - 1;
    if (node->leaf) {
        while (i >= 0 && node->keys[i] > k) {
            node->keys[i + 1] = node->keys[i];
            i--;
        }
        node->keys[i + 1] = k;
        node->n++;
    } else {
        while (i >= 0 && node->keys[i] > k) {
            i--;
        }
        i++;
        if (node->C[i]->n == 2*T-1) {
            splitChild(node, i, node->C[i]);
            if (node->keys[i] < k) {
                i++;
            }
        }
        insertNonFull(node->C[i], k);
    }
}

// 分裂子节点
void splitChild(BTreeNode* parent, int i, BTreeNode* fullChild) {
    BTreeNode* newChild = createNode(fullChild->leaf);
    newChild->n = T - 1;

    for (int j = 0; j < T-1; j++) {
        newChild->keys[j] = fullChild->keys[j + T];
    }

    if (!fullChild->leaf) {
        for (int j = 0; j < T; j++) {
            newChild->C[j] = fullChild->C[j + T];
        }
    }

    fullChild->n = T - 1;

    for (int j = parent->n; j >= i + 1; j--) {
        parent->C[j + 1] = parent->C[j];
    }

    parent->C[i + 1] = newChild;

    for (int j = parent->n - 1; j >= i; j--) {
        parent->keys[j + 1] = parent->keys[j];
    }

    parent->keys[i] = fullChild->keys[T - 1];
    parent->n++;
}

// 插入一个键到B树
void insert(BTreeNode** root, int k) {
    BTreeNode* r = *root;
    if (r->n == 2*T-1) {
        BTreeNode* s = createNode(0);
        *root = s;
        s->C[0] = r;
        splitChild(s, 0, r);
        insertNonFull(s, k);
    } else {
        insertNonFull(r, k);
    }
}

// 中序遍历B树
void traverse(BTreeNode* root) {
    int i;
       // 中序遍历节点中的所有键
    for (i = 0; i < root->n; i++) {
        // 如果不是叶子节点,先遍历子树
        if (!root->leaf) {
            traverse(root->C[i]);
        }
        printf("%d ", root->keys[i]);
    }
    // 最后遍历最右子树
    if (!root->leaf) {
        traverse(root->C[i]);
    }
}

// 搜索键 k
BTreeNode* search(BTreeNode* root, int k) {
    int i = 0;
    // 查找当前节点中的键
    while (i < root->n && k > root->keys[i]) {
        i++;
    }
    // 找到键,返回当前节点
    if (i < root->n && k == root->keys[i]) {
        return root;
    }
    // 如果是叶子节点,说明键不存在
    if (root->leaf) {
        return NULL;
    }
    // 继续在子树中查找
    return search(root->C[i], k);
}

int main() {
    BTreeNode* root = createNode(1); // 创建一个空的B树节点作为根节点

    // 插入一些键到B树中
    insert(&root, 10);
    insert(&root, 20);
    insert(&root, 5);
    insert(&root, 6);
    insert(&root, 12);
    insert(&root, 30);
    insert(&root, 7);
    insert(&root, 17);

    printf("Traversal of the constructed B-Tree is:\n");
    traverse(root);
    printf("\n");

    int key = 6;
    BTreeNode* result = search(root, key);
    if (result != NULL) {
        printf("Key %d found in B-Tree.\n", key);
    } else {
        printf("Key %d not found in B-Tree.\n", key);
    }

    return 0;
}
代码说明
  1. createNode: 创建一个新的B树节点。

  2. insertNonFull: 向一个非满节点插入一个键。

  3. splitChild: 分裂一个满节点为两个节点。

  4. insert: 插入一个新的键到B树中。

  5. traverse: 中序遍历B树,输出所有节点的键。

  6. search: 在B树中搜索一个键,找到则返回包含该键的节点,否则返回NULL

执行效果
  1. 插入了几个键后,树中将进行自动分裂和调整以保持B树的平衡特性。

  2. 使用traverse函数将打印B树中的所有键。

  3. 使用search函数可以在B树中搜索某个键并返回结果。

如果需要对B树进行更复杂的操作(如删除节点),可以继续扩展此基础实现。B树广泛用于数据库索引和文件系统管理,非常适合处理大规模数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2167189.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

观测云产品更新 | 场景、基础设施、用户访问、管理等

观测云更新 Breaking Changes 拨测标签&#xff1a;字段名由 tags.info 调整为 df_label 。 场景 1、仪表板新增历史版本记录&#xff1a;可查看此仪表板三个月内保存的版本记录&#xff0c;选中某版本后&#xff0c;可查看此版本图表详情&#xff0c;并以 json 格式、通过…

2024源代码加密软件分享TOP10丨保护源代码安全不泄露

在2024年&#xff0c;随着技术的不断进步&#xff0c;源代码加密软件也愈发成熟&#xff0c;为开发者和企业提供了更强大的保护手段&#xff0c;以应对日益严峻的数据安全挑战。以下是本年度推荐的TOP10源代码加密软件&#xff0c;它们各自具有独特的优势和特点&#xff0c;能够…

Nature | 浙江大学张龙:AARS1/2调控cGAS乳酸化并抑制固有免疫

景杰生物 | 报道 cGAS&#xff08;环状鸟苷酸-腺苷酸合成酶&#xff09;作为细胞质DNA感受器&#xff0c;是哺乳动物对抗微生物入侵的主要机制基础&#xff0c;且在抗肿瘤免疫方面也发挥作用。近日&#xff0c;被誉为诺贝尔奖“风向标”的生物医学领域重要奖项——拉斯克奖&…

8583报文解析(二)

参考 Demo&#xff1a;https://github.com/WTCool666/Iso8583/tree/master 一、【8583】ISO8583报文解析 ISO8583报文&#xff08;简称8583包&#xff09;又称8583报文&#xff0c;是一个国际标准的包格式&#xff0c;最多由128个字段域组成&#xff0c;每个域都有统一的规定&…

爆了爆了!清华大学出版《自然语言处理:原理、方法与应用》自然语言处理直通车!

今天给大家介绍一本重量级大模型书籍 《自然语言处理&#xff1a;原理、方法与应用》 《自然语言处理&#xff1a;原理、方法与应用》 是由王志立、雷鹏斌、吴宇凡合著的一本专业书籍&#xff0c;于2023年3月由清华大学出版社出版。这本书系统地阐述了自然语言处理&#xff08…

《虚空混蛋》风灵月影修改器进阶教程:掌控宇宙,肆意遨游星海

在《虚空混蛋》的浩瀚星际中&#xff0c;想要成为无畏的宇宙海盗&#xff0c;风灵月影修改器将是你的秘密武器。 下面的指南将揭示如何巧妙使用修改器&#xff0c;为你的星际征程插上翅膀。 1.准备工作&#xff1a; 从官方渠道获取最新版《虚空混蛋》风灵月影修改器并安装。确…

UnityHub下载任意版本的Unity包

1)先打开 // 也可以采用2直接打开 2)也可以直接打开 下载存档 (unity.com) 3)关联起来UnityHub即可

脚本命令类恶意代码——VBS混淆脚本分析方法

语法使用 控制流语句 分析恶意代码时&#xff0c;掌握条件语句和循环语句的工作原理及解混淆的技巧非常重要&#xff0c;因为恶意代码的作者通常会使用这些方法来复杂化代码逻辑、隐藏恶意行为并增加对分析人员的困难。 条件语句 If...Then...Else语句 If...Then...Else语…

【H2O2|全栈】关于CSS(7)CSS基础(六)

目录 CSS基础知识 前言 准备工作 元素的显示与隐藏 display visibility 元素不透明度 RGBa 十六进制 opacity 元素的溢出属性 元素的滚动条 居中布局 盒子水平居中 盒子垂直居中 盒子中心居中 网页的部分结构 顶部导航的编写技巧 轮播图的编写技巧 预告和…

压缩文件被加密?暴力拆锁!让加密文件无处遁形!

压缩包密码忘记了怎么办&#xff1f; 可以使用解密文件密码恢复软件&#xff0c;将可能存在的字符勾选&#xff0c;就可以进行密码恢复了 类似Ziperello&#xff1a; 选择你需要解密的zip压缩包后&#xff0c;勾选密码字符&#xff0c;如果完全忘记了密码&#xff0c;可以将其…

maven打包出现java.lang.OutOfMemoryError: Java heap space

&#x1f306; 内容速览 &#x1f315; 报错信息&#x1f315; 解决办法 &#x1f315; 报错信息 通过maven打包语句&#xff1a;mvn clean package -DskipTests -Ddockerfile.build.skip -Ptest -T 12 打包的时候出现报错java.lang.OutOfMemoryError: Java heap space&#xf…

关于 GitHub 的奇技淫巧

介绍下多年来使用 GitHub 所了解到的技巧 ‍ 学会看文档 如何学习使用 GitHub 呢&#xff1f;最好的方式就是&#xff1a;阅读官网文档。 官方文档通常比任何教程都 全面、权威、准确。网上教程和文章满天飞&#xff0c;但都是建立在官方文档的基础上&#xff0c;一旦官方文…

B站UP主视频素材去哪找?如何下载爆款视频素材?

大家好&#xff0c;今天我们来聊聊B站UP主们常用的视频素材来源。制作视频的朋友们都知道&#xff0c;寻找优质素材不仅费时&#xff0c;还很重要。但好的素材能让你的视频瞬间提升档次。以下是一些推荐的网站&#xff0c;帮助你找到并下载精彩的视频素材。 蛙学网 蛙学网提供了…

为什么美联储降息和我国刺激措施可能提振铜价

美联储降低利率通常对铜价产生积极影响。这主要是由于利率与美元汇率之间的关系。当美联储降息时&#xff0c;往往会使美元对其他货币贬值。 由于全球市场上的铜价是以美元计价的&#xff0c;美元走弱会使用其他货币购买的金属价格更便宜。这可能刺激来自国际买家的需求&#x…

力扣 简单 876.链表的中间结点

文章目录 题目介绍题解 题目介绍 题解 法一&#xff1a; class Solution {public ListNode middleNode(ListNode head) {ListNode cur head;int n 0;while (cur ! null) {n;cur cur.next;}ListNode curr head;for (int i 0; i < n / 2; i) {curr curr.next;}return …

一个基于共享内存的内存数据库:4 编程参考

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…

Jenkins配置Git和Maven

1、Git设置 1、上传文件 将git压缩包上传到服务器上 2、解压压缩包 tar -zxvf git-2.33.0.tar.gz 3、安装所需依赖 yum install curl-devel expat-devel gettext-devel openssl-devel zlib-devel gcc perl-ExtUtils-MakeMaker 【输入 y 】 【报错】 执行“安装所需依赖”的命…

Spring Cloud 工程搭建服务注册_服务发现

文章目录 Spring Cloud 工程搭建服务拆分示例数据库工程搭建构建父子工程创建父工程创建子项目完成两个接口 远程调用实现添加ProductInfo字段定义RestTemplate修改OrderService 服务注册/服务发现 - Eureka注册中心CAP理论常见的注册中心ZookeeperEurekaNacos Eureka 介绍搭建…

双十一好物清单分享?五款超值的数码好物分享!

双十一马上就来啦&#xff0c;大家是不是都等着在这个时候买点好东西呀&#xff1f;数码产品可是咱们生活里少不了的&#xff0c;能让咱们的生活更方便、更有意思。我这儿给大家挑了五款特别值的数码好东西&#xff0c;准备来跟大家分享分享&#xff01;快来看看有没有你中意的…

构建Spring Boot在线购物商城

第1章 绪论 1.1 课题背景 当今社会是一个互联网的社会,随着互联网的发展,信息数字化时代已经来临。互联网已经成为了新的风口&#xff0c;百度、阿里巴巴、腾讯则是中国互联网公司中的领头羊&#xff0c;互联网拉近了人与人之间的距离&#xff0c;同时也让我们的生活变得更加便…