C和指针---ADT:链表、堆栈、队列和树

程序员数据结构代码题库:堆栈、树、链表、字符串 数据结构是计算机存储、组织数据的方式,它决定了算法的效率以及解决问题的可行性。理解数据结构,可以帮助我们选择最合适的方法来存储和检索信息,从而提高程序的性能。堆栈通常有两种表示方法:数组表示的顺序堆栈和链表表示的链式堆栈。在顺序堆栈中,栈顶指针始终指向栈中最后一个元素的下一个位置;而在链式堆栈中,栈顶指针指向最后一个入栈的节点。堆栈的特性主要体现在它的操作上:有序性:元素的添加和移除都遵循LIFO原则。动态性:堆栈的大小会随着元素的入栈和出栈动态变化。安全性。 阅读详情

1.内存分配

ADT如何获取内存来存储值?三种方案:静态数组、动态分配的数组和动态分配的链式结构。
静态数组要求结构的长度固定,而且长度必须在编译时确定,方案简单,最不容易出错
动态数组,可在运行中决定数组长度,
链式结构提供最大程度的灵活性,每个元素在需要时才单独进行分配,除了不能超过机器的可用内存之外,这种方式对元素的数量几乎没有什么限制,但链式结构的链接字段需要消耗一定的内存。

2.堆栈

堆栈(stack)最鲜明的特点是其后进先出的方式
2.1 堆栈接口
基本的堆栈操作通常被称为push和pop。push是把一个新值压入到堆栈顶部,pop是把堆栈顶部的值移出堆栈并返回这个值。
2.2 实现堆栈
堆栈是最容易实现的ADT,基本方法:当值被push到堆栈时把它们存储于数组中连续的位置上,记住最近一个被push的值的下标。如果需要执行pop操作,只需要简单的减少这个下标的值即可。
/一个堆栈模块的接口/
#define STACK_TYPE int /堆栈存储的值的类型/

/push:把一个新值压入到堆栈中,它的参数是需要被压入/
void push(STACK_TYPE value);

/pop:从堆栈弹出一个值,并将其丢弃/
void pop(void);

/top:返回堆栈顶部元素的值,但不对堆栈进行操作/
STACK_TYPE top(void);

/is_empty 如果堆栈为空,返回ture,否则返回FASLE/
int is_empty(void);

/is_full 如果堆栈为满,返回ture,否则返回FASLE/
int is_full(void);
2.2.1 动态数组堆栈
在静态数组堆栈实现的基础上,增加两个新的函数,创建和销毁堆栈,主要是内存的申请与销毁

2.2.2 链式堆栈

由于只有堆栈的顶部元素才可以访问,所以使用单链表就可以很好的实现链式堆栈,把一个新元素压入到堆栈是通过在链表的起始位置添加一个元素实现。从堆栈中弹出一个元素是通过从链表中移除第1个元素实现的。位于链表头部的元素总是很容易被访问。
/*
**一个用链表实现的堆栈,没有长度限制
*/
#include “stack.h”
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>

#define FALSE 0

/*
** 定义一个结构以存储堆栈元素,其中link字段指向堆栈的下一个元素
*/
typedef struct STACK_NODE
{
STACK_TYPE value;
struct STACK_NODE next;
}StackNode;
/

** 指向堆栈中第一个节点的指针
*/
static StackNode *stack;

void create_stack(size_t size)
{
}
void destroy_stack()
{
while (!is_empty())
{
pop();
}
}

void push(STACK_TYPE value)
{
StackNode *new_node;
new_node = malloc(sizeof(StackNode));
assert(new_node != NULL);
new_node->value = value;
new_node->next = stack;
stack = new_node;
}

void pop (void)
{
StackNode *first_node;
assert(!is_empty);
first_node = stack;
stack = first_node->next;
free(first_node);
}

STACK_TYPE top()
{
assert(!is_empty);
return stack->value;
}

int is_empty()
{
return stack == NULL;
}

int is_full()
{
return FALSE;
}

3.队列

队列和堆栈的不同:队列时一种先进先出的结构。排队时一种典型的队列,首先轮到的是排在队伍最前面的人,新入队的人总是排在队伍后面。
3.1 队列接口
/*
**一个队列模块的接口
*/
#include <stdlib.h>
#define QUEUE_TYPE int /队列元素的类型/
/

**创建一个队列,参数指定队列可以存储的元素的最大数量,这个函数只是适用于动态分配数值的队列
/
void create_queue(size_t size);
/

**销毁一个队列,注意这个函数只适用于链式和动态分配数值的队列
/
void destroy_queue();
/

**向队列添加一个新元素,参数就是需要增加的元素
/
void insert(QUEUE_TYPE value);
/

**从队列中移除一个元素并将其丢弃
/
void delete(void);
/

**返回队列中第一个元素的值,但不修改队列本身
/
QUEUE_TYPE first(void);
/

**如果队列为空,返回TRUE,否则返回FALSE
/
int is_empty();
/

**如果队列已满,返回TRUE,否则返回FALSE
/
int is_full();
3.2 实现队列
队列的实现比堆栈要难的多,它需要两个指针:一个指向队头(front),一个指向队尾(rear)。堆栈总是扎根于数据的一端,但当队列的元素插入和删除时,所使用的是数组中的不同元素。
测试队列是否为空的两种方法:
1.引入一个新的变量,用于记录队列中的元素数值,它在每次插入元素时加1,在每次删除元素时减1,对这个变量的值进行测试就可以容易的分清队列空间的空与满
2.重新定义“满”:如果使用数组中的一个元素始终保持不用,这样当队列“满”时,front与rear的值便不同,通过不允许数组完全填满,问题得以避免。
当队列为空时,rear的值必须比front小1。
3.3 数组队列的实现
用一个静态数组实现一个队列,使用“不完全填满数组”的技巧来区分空队列和满队列。
/

**一个静态数组实现的队列,数组的长度只能通过修改#define定义并重新编译模块来调整
/
#include “queue.h”
#include <stdio.h>
#inclued <assert.h>
#define QUEUE_SIZE 100 /队列中元素的最大数值/
#define ARRAY_SIZE (QUEUE_SIZE + 1) /数组的长度/
/

**用存储队列元素的数值和指向队列头和尾的指针
*/
static QUEUE_TYPE queue[ARRAY_SIZE ];
static size_t front = 1;
static size_t rear = 0;

void insert(QUEUE_TYPE value)
{
assertf(!is_full());
rear = (rear + 1) % ARRAY_SIZE;
queue[rear] = value;
}
void delete()
{
assert(!is_empty());
front = (front + 1) % ARRAY_SIZE;
}
QUEUE_TYPE first()
{
assert(!is_empty());
return queue[front];
}
int is_empty()
{
return (rear+1)%ARRAY_SIZE ==front;
}
int is_full()
{
return (rear+2)%ARRAY_SIZE ==front;
}

4.树

树是一种数据结构,要么为空,要么具有一个值并具有零个或多个孩子。二叉树是树的一种特殊形式,每个节点至多有两个孩子,称为左孩子(left)和右孩子(right)。
二叉树常见的特例:二叉搜索树、堆和红黑树。
二叉搜索树具有一个额外的属性:每个节点值比它的左子树的所有节点的值都要大,但比它的右子树的所有节点的值都要小。
堆分为最大堆和最小堆,在最大堆中,根节点的值最大,在最小堆中根节点的值最小。最大值和最小值的问题可以用堆来解决。
红黑树是把书中的节点定义为红、黑两种颜色,并通过规则确保从根节点到叶节点的最长路径的长度不超过最短路径的两倍。
4.1 在二叉搜索树中插入
保持二叉搜索树的属性,其基本算法如下:
如果树为空:
把新值作为根节点插入
否则:
如果新值小于当前节点的值:
把新值插入到当前节点的左子树。
否则:
把新值插入到当前节点的右子树
4.2 从二叉搜索树删除节点
三种情况:删除没有孩子的节点;删除只有一个孩子的节点;删除有两个孩子的节点。
删除没有孩子的节点:删除一个叶节点不会导致任何子树断开,所以不存在重新连接的问题。
删除只有一个孩子的节点:把这个节点的双亲节点与它的孩子连接起来
删除有两个孩子节点:如果一个节点有两个孩子,它的双亲不能连接到它的两个孩子,解决这个问题的一种策略是不删除这个节点,而是删除它的左子树中值最大的那个节点,并用这个值代替原先应被删除的那个节点的值。
4.3 在二叉搜索树中查找
如果树为空:
这个值不存在于树中
否则:
如果这个值和根节点的值相等:
成功找到这个值
否则:
如果这个值小于根节点的值:
查找左子树
否则:
查找右子树
4.4 树的遍历
遍历树的节点有几种不同的次序,最常用的时前序、中序、后序和层次遍历。所有类型的遍历都是从树的根节点或你希望开始遍历的子树的根节点开始。
前序遍历:检查节点的值,然后递归的遍历左子树和右子树。
中序遍历:首先遍历左子树,然后检查当前节点的值,最后遍历右子树。
后序遍历:首先遍历左右子树,然后检查当前节点的值。
层次遍历:首先处理根节点,接着是它的孩子,再接着是它的孙子。

5.链式二叉搜索树

/*
**一个使用动态分配的链式结构实现的二叉搜索树
*/
#include “tree.h”
#include <stdio.h>
#include <malloc.h>

/*
**TreeNode 结构包含了值和两个指向某个树节点的指针
*/
typedef struct TREE_NODE
{
TREE_TYPE value;
struct TREE_NODE *left;
struct TREE_NODE right;
} TreeNode;
/

**指向树根节点的指针
*/
static TreeNode *tree;

void insert(TREE_TYPE value)
{
TreeNode *current;
TreeNode **link;

/*
**从根节点开始
*/
link = &tree;
	/*
**持续查找值,进入合适的子树
*/
while ((current = *link) != NULL)
{
/*
**根据情况,进入左子树或右子树(确认没有出现重复的值)
*/
	if (value < current->value)
	{
		link = &current->left;
	}
	else
	{
		assert(value != current->value);
		link = &current->right;
	}
}

}
/*
**分配一个新节点,适当节点的link字段指向它
*/
current = malloc(sizeof(TreeNode));
assert(current != NULL);
current->value = value;
current->left = NULL;
current->right = NULL;
*link = current;

TREE_TYPE *find (TREE_TYPE value)
{
TreeNode current;
/

**从根节点开始,直到找到这个值,进入合适的子树
*/
current = tree;
while (current != NULL && current->value != value)
{
if (value < current->value)
current = current->left;
else
current = current->right;
}
if (current != NULL)
return &current->value;
else
return NULL;
}

C语言实现五大核心数据结构详解 链表由多个节点组成,每个节点包含数据部分和指向下一个节点的指针部分。链表的基本结构如下图所示:graph LRA[节点1] --> B[节点2]B --> C[节点3]链表可以分为以下几种类型:分类名称特点说明单链表每个节点只有一个指向后继节点的指针双链表每个节点有两个指针,分别指向前驱和后继节点循环链表首尾相连,最后一个节点指向第一个节点带头节点链表在链表头部增加一个不存储数据的哨兵节点,简化操作逻辑。 阅读详情

相关推荐

【读代码】TradingAgents:基于多智能体LLM的金融交易框架深度解析

TradingAgents是由Tauric Research团队开源的创新型金融交易框架,其核心思想是通过多智能体协作系统模拟专业交易机构的决策流程。项目采用模块化设计,整合了LLM、实时数据分析、风险控制等组件,实现了从市场分析到交易执行的完整闭环。

kakaZhui的博客 2003

C_栈和队列(ADT)-队列的非循环(带头指针)顺序表示和实现

队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。 顺序队列一次性要分配大量保证够用的空间,效率较高,因为是基于数组的,长度也是固定的。可以实现变长,但是一般代价较高。 队列的数据元素

Cynical丶Gary_博客 504

【高级-RAG-优化方法】

本文介绍了两种优化RAG(检索增强生成)系统的高级方法。第一部分介绍KnowFlow项目,它采用父子分块技术,将文档分为父分块(800-1500字符)和子分块(200-400字符),通过精确匹配子分块再返回父分块内容来保证搜索精确性和上下文完整性。第二部分探讨Milvus的多种增强技术,包括查询增强(如假设问题生成、回溯提示)、索引增强(自动合并块、分层索引)、检索器增强(句子窗口检索、元数据过滤)、生成器增强(提示压缩、块排序)以及管道增强(自我反省、代理查询路由)。这些方法共同提升了RAG系统的检索效率

weixin_48585108的博客 960

堆栈、指针、队列、链表之间有什么区别?

weixin_45912307的博客 926

Langchain4j 文档处理实战:从加载到分割的完整流程解析

本文详细解析了使用Langchain4j进行文档处理的完整流程,涵盖从文档加载、解析到分割的核心步骤。通过实战代码示例,重点介绍了如何利用文档分割器将大文档切割为适合大语言模型处理的片段,并提供了参数调优与避坑指南,帮助Java开发者高效构建AI应用的数据处理基础。

smartcontract5的博客 542

Qt + Robot Interface实现上位机和发那科机器人通信

摘要: 本文详细介绍了FANUC机器人的RobotInterface模块开发流程,包括环境配置、通信连接和上位机开发等内容,并提供了数值寄存器、位置寄存器和当前位置的读写代码等示例。适用于自动化行业有通讯需求的上位机开发人员,保姆教程,超详细版,新手也可以根据示例开发自己的通信程序。

xyhkma的博客 1750

C/C++ - 数据结构(链表、栈、队列、树(二叉树))、动态数组

用递归 减少运行时间 通过递归,缩小问题的范围。O(logN) 不用递归 1.递归调用之后,实际上没有必要知道存在的值 比如: //(尾递归) 尾递归可以通过将代码放到一个while循环中并用每个方法参数的一次赋值代替递归调用而被手工能消除。 //(尾递归) public static <T> void printList(Iterator<T> itr){ if(!...

LawssssCat的博客 1345

SAP交货单过账避坑指南:序列号处理、Buffer清理与BAPI提交回滚的那些事儿

本文深入解析SAP交货单过账中的序列号处理、Buffer清理与BAPI提交回滚等关键问题,提供WS_DELIVERY_UPDATE和BAPI_OUTB_DELIVERY_CONFIRM_DEC的实战优化方案。通过详细的技术分析和最佳实践,帮助开发者避免常见陷阱,提升交货单处理的稳定性和效率。

weixin_31155097的博客 431

链表实现stack和queue,java实现(ADT思想)

第一部分: 链表实现Stack 1 package com.liu.Link; 2 3 //栈处理类 4 public class LinkStack3 { 5 private LinkList3 theList; 6 //构造函数防止空指针异常错误 7 public LinkStack3() 8 { 9...

weixin_30817749的博客 253

OceanBase容量统计:租户、数据库、表大小

🍎 数据库版本:OceanBase V4。

Sebastien23的博客 1400

用 AI 设计力打造专业 UI_UX:在 Trea、Qoder 等 AI IDE 中集成 ui-ux-pro-max-skill

的核心是知识库Trea 和 Qoder 虽未被--ai all原生支持,但完全可通过@folder手动集成使用后,你的 AI 生成代码将从“功能可用”跃升至“设计专业”这是零成本提升产品质感的最佳实践之一🎨好的 UI 不应是设计师的专利,而是每个开发者的默认能力。然后在 Trea 或 Qoder 中输入—— 让 AI 成为你最懂设计的结对编程伙伴。

lpfasd123的博客 7101

指针学习日记(五)经典抽象数据类型、标准函数库

抽象数据类型(ADT)是C程序员不可或缺的工具,这是由他们的属性所决定。 这类ADT有链表,堆栈,队列,树等。 内存分配: 所有ADT都需要确定一件事情——如何获得内存来存储值。有3种可选方案: 1.静态数组:长度固定,最为简单 2.动态分配的数组:可以运行时再决定数组的长度。如果需要的话,可以分配一个新的更大的数组,再把原来数组元素复制到新数组,然后删除原先的数组,从而动态改变数组长度的目的。 3.动态分配的链式结构:提供了最大程度的灵活性,这种方式对元素的数量几乎无限制,但是链式结构的链接字段需要消耗一

qq_42677487的博客 119

使用Qt Creator自带的Qt Designer构造UI界面流程总结

在本文中,我们将总结使用Qt Creator自带的Qt Designer构造UI界面的流程。在对话框中,您可以选择一个控件的信号,然后将其连接到另一个控件的槽。例如,您可以将按钮的点击信号连接到一个槽函数,以响应按钮的点击事件。右键单击窗口设计器中的空白区域,选择适当的布局管理器,如水平布局、垂直布局或网格布局。在Qt Designer中,您可以使用各种预定义的UI控件来设计应用程序的界面。现在,您可以在应用程序的源代码中使用生成的UI界面。在您的源文件中,包含相应的头文件,然后创建一个UI界面的实例。

cl6789的博客 1393

C语言实现链表、堆栈和队列

通过C语言实现单向链表、有序链表、循环链表、数组堆栈、链式堆栈以及对了,并且给出了一种堆栈的面向对象形式。

微小冷的学习笔记 3051

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

廖雪峰Python教程[完整版]

廖雪峰的python教程整理的,已经排好版了,而且还是完整的,适合小白

CAndPrimer_17 关于堆栈,队列,树的基础理解(ADT)

文章目录C和指针第十七章 一些数据结构的问题 笔记1.关于堆栈 Stack1.1用数组的形式实现1.2用链表的形式实现2.关于队列 Queue2.1用数组实现 Queue2.2用链表实现 Queue3.关于树 Tree3.1简单的二叉搜索树(Binary search tree)BST3.2用数组实现 BST3.3用链表实现 BST4.感悟 C和指针第十七章 一些数据结构的问题 笔记 Dargon 2020/11/05 所遇到的的重要的问题 教科书 来自:《C And Primer》第十七章

Dallas01的博客 302

温度PID控制PLC程序

温度PID稳定控制程序,适用于欧姆龙PLC,对其他PLC也具有很大参考价值

ADT知识

ADT,全程Abstract data type,即抽象数据类型。c和指针的ADT主要包括链表、堆栈、队列和树。c和指针的第十二章讲述的是链表。第十三章讲述的是堆栈、队列和树。提示:以下是本篇文章正文内容,下面案例可供参考提示:这里对文章进行总结:例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。

晴山の博客 722

最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版

Part-E1-SDIO-Specification-Ver4.00-Final-120220.pdf:最新的sdio 4.0 spec 协议标准 带书签 高清完整PDF版,包括SDIO 接口的外设,SDIO 接口官方协议等。

数据结构与算法 知识点总结(中)---线性表,堆栈,队列

Table of Contents 数据结构概念 常见数据结构 . 数组 数组下标运算法: 数组程序设计 . 线性表 链表Linked List 单向链表: 双向链表: 循环链表 单向、双向、循环链表区别: 链表的应用: C代码: 接口声明 接口实现 . 堆栈 2.1 操作 2.2 特点 2.3 抽象定义 2.4 软件堆栈 2.4.1 数组堆栈 2.4....

Techblog of HaoWANG 1688

c语言链表和fifo,FIFO 队列的链表和数组实现

FIFO 队列的链表和数组实现数据结构FIFO (First-in, First-out,先进先出)队列:当执行delete操作时删除那些呆在队列中时间最长的元素。FIFO 队列是这样一个ADT,包含两个基本操作:插入(put)一个新的项、删除(get)一个最早插入的项。一、FIFO队列的链表实现FIFO 队列和下堆栈的区别在于新项的插入是在尾部,而不是在头部。因此实现程序要保存一个指向链表最后一...

weixin_34274163的博客 738

第17章 经典抽象数据类型

有些抽象数据类型(ADT)是C程序员不可或缺的工具,这是由于它们的属性决定的。这类ADT有链表、堆栈、队列和树等。 内存分配 所有的ADT都必须确定一件事情——如何获取内存来存储值。有3种可选的方案:静态数组、动态分配数组和动态分配的链式结构。 静态数组要求结构的长度固定,而且这个长度必须在编译时确定。但这个方案最为简单,而且最不容易出错。 如果使用动态数组,可以在运行时才决定数组的长度。而且如果需要的话,可以通过分配一个新的、更大的数组,把原来数组的元素复制到新数组中,然后删除原先的数组,从而达到动态改变

oruchimaru0420的博客 240

FIFO 队列的链表和数组实现

FIFO (First-in, First-out,先进先出)队列:当执行delete操作时事删除那些呆在队列中时间最长的元素。 FIFO 队列是这样一个ADT,包含两个基本操作:插入(put)一个新的项、删除(get)一个最早插入的项。 FIFO 队列的链表实现和数组实现

quinn的专栏 5035

c语言叫队列作用及用法,C语言 表、栈和队列详解及实例代码

C语言 表、栈和队列详解表ADT形如A1,A2,A3…An的表,这个表的大小为n,而大小为0的表称为空表,非空表中,Ai+1后继Ai,Ai-1前驱Ai,表ADT的相关操有PrintList打印表中的元素;CreateEmpty创建一个空表;Find返回关键字首次出现的位置;Insert和Delete从表的某个位置插入和删除某个关键字。对表的所有操作都可以通过使用数组来实现,但在这里使用链表的方式来...

weixin_42361026的博客 203

详解堆栈的几种实现方法——C语言版

基本的抽象数据类型(ADT)是编写C程序必要的过程,这类ADT有链表、堆栈、队列和树等,本文主要讲解下堆栈的几种实现方法以及他们的优缺点。   堆栈(stack)的显著特点是后进先出(Last-In First-Out, LIFO),其实现的方法有三种可选方案:静态数组、动态分

Dream Fly的专栏 3万+

linux堆栈有什么作用,嵌入式世界里,堆栈的作用和意义

描述栈这种结构在嵌入式里其实是非常常用的,比如函数调用与返回就是典型的栈应用,虽然很多时候栈都是CPU系统在自动管理,我们只需要在链接文件里分配栈大小以及栈存放位置,但稍微了解一下栈的原理会更加利于我们去理解嵌入式代码执行机制,以及帮助我们进一步去调试。1. 何为堆栈?堆HEAP与栈 STACK 是两个不同概念,其本质上都是一种数据结构。栈是一种按数据项排列的数据结构,只能在一端(栈顶 t...

weixin_39999190的博客 743

c语言链表和fifo,FIFO 行列的链表和数组实现

FIFO 队列的链表和数组实现FIFO (First-in, First-out,先进先出)队列:当执行delete操作时删除那些呆在队列中时间最长的元素。FIFO 队列是这样一个ADT,包含两个基本操作:插入(put)一个新的项、删除(get)一个最早插入的项。一、FIFO队列的链表实现FIFO 队列和下堆栈的区别在于新项的插入是在尾部,而不是在头部。因此实现程序要保存一个指向链表最后一个节点的...

weixin_35645652的博客 498
上一篇: C和指针---标准函数库
下一篇: C陷阱与缺陷---语法陷阱和ASCII
ldxFashion
博客等级 码龄6年 0粉丝 21原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值