《数据结构》栈,队列,双向链表

目录

栈概念

顺序栈

链式栈(链表实现)

顺序栈和链式栈的区别是什么?

队列

队列概念

顺序队列

链式队列

双向链表


栈概念

  • 什么是栈?

只能在一端进行插入和删除数据的线性表(称为栈),把能进行插入和删除的这一端叫栈顶,另一端成为栈底。实现栈可以用顺序表实现(顺序栈),也可以用链表实现(链式栈)

  • 栈的特点

先进后出:first in last out FILO

后进先出:last in first out LIFO

顺序栈

  • 逻辑结构:线性结构
  • 存储结构:顺序存储
  • 定义一个结构体描述顺序栈的信息
typedef  int   datatype_t;
typedef struct
{datatypde_t *data;	//保存栈的地址(数组)int  top;			//保存栈顶数据的下标int  len;			//栈的大小
}seqstack_t,*seqstack_p;
栈的常用操作
#include <stdio.h>
#include <stdlib.h>typedef int datatype_t;
typedef struct {datatype_t *data;   // 保存栈的地址(数组)int top;            // 保存栈顶数据的下标int len;            // 栈的大小
} seqstack_t, *seqstack_p;// 1. 创建一个空栈
seqstack_p createStack(int size) {seqstack_p stack = (seqstack_p)malloc(sizeof(seqstack_t));if (stack == NULL) {printf("Failed to allocate memory for stack.\n");return NULL;}stack->data = (datatype_t*)malloc(size * sizeof(datatype_t));if (stack->data == NULL) {printf("Failed to allocate memory for stack data.\n");free(stack);return NULL;}stack->top = -1;stack->len = size;return stack;
}// 2. 入栈
int push(seqstack_p stack, datatype_t value) {if (stack->top == stack->len - 1) {printf("Stack is full. Cannot push %d.\n", value);return 0;}stack->top++;stack->data[stack->top] = value;return 1;
}// 3. 判断栈是否满
int isFull(seqstack_p stack) {return stack->top == stack->len - 1;
}// 4. 出栈
int pop(seqstack_p stack, datatype_t *value) {if (stack->top == -1) {printf("Stack is empty. Cannot pop.\n");return 0;}*value = stack->data[stack->top];stack->top--;return 1;
}// 5. 判断栈是否为空
int isEmpty(seqstack_p stack) {return stack->top == -1;
}// 6. 求栈的长度
int stackLength(seqstack_p stack) {return stack->top + 1;
}// 7. 获取栈顶的值
int getTop(seqstack_p stack, datatype_t *value) {if (stack->top == -1) {printf("Stack is empty. Cannot get top value.\n");return 0;}*value = stack->data[stack->top];return 1;
}int main() {int size = 5;seqstack_p stack = createStack(size);if (stack == NULL) {return 1;}push(stack, 1);push(stack, 2);push(stack, 3);int topValue;if (getTop(stack, &topValue)) {printf("Top value: %d\n", topValue);}printf("Stack length: %d\n", stackLength(stack));while (!isEmpty(stack)) {int value;pop(stack, &value);printf("Pop value: %d\n", value);}free(stack->data);free(stack);return 0;
}

链式栈(链表实现)

  • 逻辑结构:线性结构
  • 存储结构:链式存储
  • 定义节点结构
typedef int datatype_t;
typedef struct node_t
{datatype_t data;		//数据struct node_t *next;	//节点
}linkstack_t,*linkstack_p;
  • 链式栈的操作
#include <stdio.h>
#include <stdlib.h>typedef int datatype_t;
typedef struct node_t {datatype_t data;struct node_t* next;
} linkstack_t, *linkstack_p;// 1. 创建一个空的栈
linkstack_p createStack() {linkstack_p stack = (linkstack_p)malloc(sizeof(linkstack_t));if (stack == NULL) {printf("Failed to allocate memory for stack.\n");return NULL;}stack->next = NULL;return stack;
}// 2. 入栈
void push(linkstack_p stack, datatype_t value) {linkstack_p newNode = (linkstack_p)malloc(sizeof(linkstack_t));if (newNode == NULL) {printf("Failed to allocate memory for new node.\n");return;}newNode->data = value;newNode->next = stack->next;stack->next = newNode;
}// 3. 判断栈是否为空
int isEmpty(linkstack_p stack) {return stack->next == NULL;
}// 4. 出栈
datatype_t pop(linkstack_p stack) {if (isEmpty(stack)) {printf("Stack is empty. Cannot pop.\n");return NULL;}linkstack_p temp = stack->next;datatype_t value = temp->data;stack->next = temp->next;free(temp);return value;
}// 5. 清空栈
void clearStack(linkstack_p stack) {while (!isEmpty(stack)) {pop(stack);}
}// 6. 求栈的长度
int stackLength(linkstack_p stack) {int count = 0;linkstack_p p = stack->next;while (p != NULL) {count++;p = p->next;}return count;
}// 7. 获取栈顶的值
datatype_t getTop(linkstack_p stack) {if (isEmpty(stack)) {printf("Stack is empty. Cannot get top value.\n");return NULL;}return stack->next->data;
}int main() {linkstack_p stack = createStack();push(stack, 1);push(stack, 2);push(stack, 3);printf("Stack length: %d\n", stackLength(stack));datatype_t topValue = getTop(stack);printf("Top value: %d\n", topValue);while (!isEmpty(stack)) {datatype_t value = pop(stack);printf("Pop value: %d\n", value);}clearStack(stack);free(stack);return 0;
}

顺序栈和链式栈的区别是什么?

(1)顺序栈的存储结构是顺序存储,链式栈的存储结构是链式存储

(2)顺序栈的长度受限制,而链栈不会

队列

队列概念

  • 什么是队列?

只允许在两端进行插入删除操作的线性表,在队尾插入,插入数据的这一端,被称为"队尾",删除的一端被称为"队头"。实现队列的方式有两种:顺序队列 链式队列

  • 队列特点

先进先出、后进后出 FIFO LILO

顺序队列

  • 逻辑结构:线性结构
  • 存储结构:顺序结构
  • 定义顺序队列的结构体
#define N 6
typedef int  datatype_t;
typedef struct 
{datatype_t  data[N];//顺序表定义的队int front;			//队头下标int  rear;			//队尾下标
}sequeue_t;  
顺序队列基础操作
#include <stdio.h>
#include <stdlib.h>#define N 6
typedef int datatype_t;
typedef struct {datatype_t data[N]; // 顺序表定义的队int front; 			// 队头下标int rear; 			// 队尾下标
} sequeue_t;// 1. 创建一个空的顺序队列
sequeue_t* createQueue() {sequeue_t* queue = (sequeue_t*)malloc(sizeof(sequeue_t));if (queue == NULL) {printf("Failed to allocate memory for queue.\n");return NULL;}queue->front = 0;queue->rear = 0;return queue;
}// 2. 入队
void enqueue(sequeue_t* queue, datatype_t value) {if ((queue->rear + 1) % N == queue->front) {	printf("Queue is full. Cannot enqueue.\n");return;}queue->data[queue->rear] = value;queue->rear = (queue->rear + 1) % N;
}// 3. 判断队列是否满
int isFull(sequeue_t* queue) {return (queue->rear + 1) % N == queue->front;
}// 4. 出队
datatype_t dequeue(sequeue_t* queue) {if (queue->front == queue->rear) {printf("Queue is empty. Cannot dequeue.\n");return NULL;}datatype_t value = queue->data[queue->front];queue->front = (queue->front + 1) % N;return value;
}// 5. 判断队列是否为空
int isEmpty(sequeue_t* queue) {return queue->front == queue->rear;
}// 6. 计算队列的长度
int queueLength(sequeue_t* queue) {return (queue->rear - queue->front + N) % N;
}// 7. 清空队列
void clearQueue(sequeue_t* queue) {queue->front = queue->rear;
}int main() {sequeue_t* queue = createQueue();enqueue(queue, 1);enqueue(queue, 2);enqueue(queue, 3);printf("Queue length: %d\n", queueLength(queue));while (!isEmpty(queue)) {datatype_t value = dequeue(queue);printf("Dequeued value: %d\n", value);}if (isEmpty(queue)) {printf("Queue is empty.\n");}clearQueue(queue);free(queue);return 0;
}

链式队列

  • 逻辑结构:线性结构
  • 存储结构:链式存储
  • 定义节点结构体
typedef   int  datatype;
typedef struct  node_t
{datatype data;	//数据域struct node_t *next;
}link_t;//保存头尾节点地址结构体:
typedef struct
{link_t *front;	//头指针link_t *rear;	//尾指针int len;		//保存队列的长度(个数)
}queue_t;
  • 链式队列的操作
#include <stdio.h>
#include <stdlib.h>typedef int datatype;typedef struct node_t {datatype data;          // 数据域struct node_t *next;    // 指向下一个节点的指针
} link_t;typedef struct {link_t *front;          // 头指针link_t *rear;           // 尾指针int len;                // 队列长度
} queue_t;// 创建空队列
void createQueue(queue_t *queue) {queue->front = NULL;queue->rear = NULL;queue->len = 0;
}// 入队
void enqueue(queue_t *queue, datatype data) {link_t *newNode = (link_t*)malloc(sizeof(link_t));newNode->data = data;newNode->next = NULL;if (queue->rear == NULL) {queue->front = newNode;queue->rear = newNode;} else {queue->rear->next = newNode;queue->rear = newNode;}queue->len++;
}// 出队
datatype dequeue(queue_t *queue) {if (queue->front == NULL) {printf("Queue is empty.\n");return -1; // 用-1表示队列为空的情况}link_t *temp = queue->front;datatype data = temp->data;queue->front = queue->front->next;free(temp);if (queue->front == NULL) {queue->rear = NULL;}queue->len--;return data;
}// 判断队列是否为空
int isQueueEmpty(queue_t *queue) {return (queue->front == NULL);
}// 清空队列
void clearQueue(queue_t *queue) {while (queue->front != NULL) {link_t *temp = queue->front;queue->front = queue->front->next;free(temp);}queue->rear = NULL;queue->len = 0;
}// 计算队列的长度
int getQueueLength(queue_t *queue) {return queue->len;
}int main() {queue_t queue;createQueue(&queue);// 测试入队enqueue(&queue, 10);enqueue(&queue, 20);enqueue(&queue, 30);// 测试出队printf("Dequeued element: %d\n", dequeue(&queue));// 测试判断队列是否为空if (isQueueEmpty(&queue)) {printf("Queue is empty.\n");} else {printf("Queue is not empty.\n");}// 测试清空队列clearQueue(&queue);// 测试计算队列的长度printf("Queue length: %d\n", getQueueLength(&queue));return 0;
}

双向链表

  • 逻辑结构:线性结构
  • 存储结构:链式存储
  • 保存数据的结构体
typede int  datatype;typedef struct node_t
{datatype data;			//数据域struct node_t *prior;	//保存前一个节点的地址struct node_t *next;	//保存后一个节点地址
}link_t;//用于保存双向链表信息的结构体:
typedef struct
{link_t *head;	//保存头节点地址link_t *tail;	//保存尾节点的地址int len;		//保存双向链表的长度
}double_t;
  • 双向链表的操作
#include <stdio.h>
#include <stdlib.h>typedef int datatype;typedef struct node_t {datatype data;          // 数据域struct node_t *prior;   // 前一个节点的指针struct node_t *next;    // 后一个节点的指针
} link_t;typedef struct {link_t *head;           // 头节点的指针link_t *tail;           // 尾节点的指针int len;                // 双向链表的长度
} double_t;// 创建一个空的双向链表
void createDoubleList(double_t *list) {list->head = NULL;list->tail = NULL;list->len = 0;
}// 向双向链表的指定位置插入数据
void insertData(double_t *list, int pos, datatype data) {if (pos < 0 || pos > list->len) {printf("Invalid position.\n");return;}link_t *newNode = (link_t*)malloc(sizeof(link_t));newNode->data = data;if (pos == 0) {newNode->prior = NULL;newNode->next = list->head;if (list->head != NULL) {list->head->prior = newNode;}list->head = newNode;if (list->tail == NULL) {list->tail = newNode;}} else if (pos == list->len) {newNode->prior = list->tail;newNode->next = NULL;if (list->tail != NULL) {list->tail->next = newNode;}list->tail = newNode;} else {link_t *current = list->head;int i = 0;while (i < pos) {current = current->next;i++;}newNode->prior = current->prior;newNode->next = current;current->prior->next = newNode;current->prior = newNode;}list->len++;
}// 遍历双向链表
void traverseList(double_t *list) {link_t *current = list->head;while (current != NULL) {printf("%d ", current->data);current = current->next;}printf("\n");
}// 删除双向链表指定位置的数据
void deleteData(double_t *list, int pos) {if (pos < 0 || pos >= list->len) {printf("Invalid position.\n");return;}link_t *current = list->head;if (pos == 0) {list->head = current->next;if (list->head != NULL) {list->head->prior = NULL;}if (list->tail == current) {list->tail = NULL;}} else if (pos == list->len - 1) {current = list->tail;list->tail = current->prior;list->tail->next = NULL;} else {int i = 0;while (i < pos) {current = current->next;i++;}current->prior->next = current->next;current->next->prior = current->prior;}free(current);list->len--;
}// 判断双向链表是否为空
int isDoubleListEmpty(double_t *list) {return (list->head == NULL);
}// 求双向链表的长度
int getDoubleListLength(double_t *list) {return list->len;
}// 查找指定数据出现的位置
int findDataPosition(double_t *list, datatype data) {link_t *current = list->head;int pos = 0;while (current != NULL) {if (current->data == data) {return pos;}current = current->next;pos++;}return -1; // 表示未找到数据
}// 修改指定位置的数据
void modifyData(double_t *list, int pos, datatype newData) {if (pos < 0 || pos >= list->len) {printf("Invalid position.\n");return;}link_t *current = list->head;int i = 0;while (i < pos) {current = current->next;i++;}current->data = newData;
}// 删除双向链表中的指定数据
void deleteDataByValue(double_t *list, datatype data) {int pos = findDataPosition(list, data);if (pos != -1) {deleteData(list, pos);} else {printf("Data not found.\n");}
}// 转置双向链表
void reverseList(double_t *list) {if (list->len <= 1) {return;}link_t *current = list->head;link_t *temp = NULL;while (current != NULL) {temp = current->prior;current->prior = current->next;current->next = temp;current = current->prior;}temp = list->head;list->head = list->tail;list->tail = temp;
}int main() {double_t list;createDoubleList(&list);// 测试向双向链表的指定位置插入数据insertData(&list, 0, 10);insertData(&list, 1, 20);insertData(&list, 2, 30);// 测试遍历双向链表traverseList(&list);// 测试删除双向链表指定位置的数据deleteData(&list, 1);// 测试判断双向链表是否为空if (isDoubleListEmpty(&list)) {printf("Double linked list is empty.\n");} else {printf("Double linked list is not empty.\n");}// 测试求双向链表的长度printf("Double linked list length: %d\n", getDoubleListLength(&list));// 测试查找指定数据出现的位置int pos = findDataPosition(&list, 20);if (pos != -1) {printf("Data found at position: %d\n", pos);} else {printf("Data not found.\n");}// 测试修改指定位置的数据modifyData(&list, 0, 50);// 测试删除双向链表中的指定数据deleteDataByValue(&list, 30);// 测试转置双向链表reverseList(&list);// 再次遍历双向链表traverseList(&list);return 0;
}

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

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

相关文章

JavaDemo——使用jks的https

java使用https主要就是设置下sslContext&#xff0c;sslContext初始化需要密钥管理器和信任管理器&#xff0c;密钥管理器用于管理本地证书和私钥&#xff0c;信任管理器用于验证远程服务器的证书&#xff0c;这两种管理器都需要KeyStore初始化&#xff0c;两种管理器可以按需只…

Ubuntu 网络配置指导手册

一、前言 从Ubuntu 17.10 Artful开始&#xff0c;Netplan取代ifupdown成为默认的配置实用程序&#xff0c;网络管理改成 netplan 方式处理&#xff0c;不在再采用从/etc/network/interfaces 里固定 IP 的配置 &#xff0c;配置写在 /etc/netplan/01-network-manager-all.yaml 或…

【事业单位-语言理解1】中心理解02

【事业单位-语言理解1】中心理解02 1.中心理解1.1 并列关系1.2 主题词1.3程度词&#xff0c;表示强调 二、标题填入题&#xff08;优先考虑主题词&#xff09;三、词句理解题 1.中心理解 解题思路 1.1 并列关系 涉及时间顺序 注意选项不要逻辑不当 并列关系的时候&…

行云创新 CloudOS 助力上汽乘用车企业云原生IT架构变革

近日&#xff0c;在2023架构可持续未来峰会成都制造业分会场上&#xff0c;上海汽车集团股份有限公司乘用车公司基础架构部主管茹洋带来了议题为《云原生时代上汽乘用车企业IT架构变革和实践》的精彩演讲。他从云原生对于企业IT架构的意义、企业IT架构变革的必要性入手&#xf…

C程序环境及预处理

​​​​​文章目录 一、程序的翻译环境和执行环境 1.程序编译过程 2.编译内部原理 3.执行环境 二、程序运行前的预处理 1.预定义符号归纳 2.define定义标识符 3.define定义宏 4.define替换规则 5.宏和函数的对比 三、头文件被包含的方式 四、练习&#xff1a;写一…

Vue3状态管理库Pinia——核心概念(Store、State、Getter、Action)

个人简介 &#x1f440;个人主页&#xff1a; 前端杂货铺 &#x1f64b;‍♂️学习方向&#xff1a; 主攻前端方向&#xff0c;正逐渐往全干发展 &#x1f4c3;个人状态&#xff1a; 研发工程师&#xff0c;现效力于中国工业软件事业 &#x1f680;人生格言&#xff1a; 积跬步…

98、简述Kafka的rebalance机制

简述Kafka的rebalance机制 consumer group中的消费者与topic下的partion重新匹配的过程 何时会产生rebalance: consumer group中的成员个数发生变化consumer 消费超时group订阅的topic个数发生变化group订阅的topic的分区数发生变化 coordinator: 通常是partition的leader节…

408专业课

1.快速排序 8.3_2_快速排序_哔哩哔哩_bilibili 优化后&#xff1a;时间复杂度O(nlogn) &#xff0c;空间复杂度O(logn) //优化后的快排 void Quick_sort(int a[], int l, int r) {if (l > r) return;把a数组中随机一个元素和a[l]交换 //快排优化int p a[l], i …

Java将数据集合转换为PDF

这里写自定义目录标题 将数据集合转换为pdf引入包工具类测试代码导出效果 将数据集合转换为pdf 依赖itext7包将数据集合转换导出为PDF文件 引入包 <properties><itext.version>7.1.11</itext.version> </properties><dependency><groupId&…

SAP 中的ABAP OPEN SQL

一、ABAP OPEN SQL语法 如果要在ABAP中使用Open SQL 需要注意使用符合其规则的语法&#xff0c;SQL过程中的变量都需要使用来转义&#xff0c;以下为普通SQL 与 Open SQL 之间的语法转换&#xff0c; 普通SQL&#xff1a; SELECT MAX( MATNR ) INTO IT_TAB-MATNRFROM MARA W…

什么是HTTP 500错误,怎么解决

目录 什么是HTTP 500 HTTP 500错误的常见原因&#xff1a; 如何修复HTTP 500 总结 什么是HTTP 500 错误 HTTP 500内部服务器错误是指在客户端发出请求后&#xff0c;服务器在处理请求过程中发生了未知的问题&#xff0c;导致服务器无法完成请求。HTTP 500错误是一个通用的服…

Mybatis-Plus(三)--Mybatis-Plus配置和条件构造器

一.配置 在MP中有大量的配置&#xff0c;其中有一部分是Mybatis原生的配置&#xff0c;另一部分是MP的配置&#xff0c;详情&#xff1a;https://mybatis.plus/config 1.基本配置 【1】configLocation--自己单独的MyBatis配置的路径 #MyBatis配置文件位置&#xff0c;如果您…

Spring-缓存初步认识

Spring-缓存 简单介绍 缓存是一种介于数据永久存储介质和数据应用之间的数据临时存储介质缓存有效提高读取速度&#xff0c;加速查询效率 spring使用缓存方式 添加依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId>spring…

海康摄像头开发笔记(一):连接防爆摄像头、配置摄像头网段、设置rtsp码流、播放rtsp流、获取rtsp流、调优rtsp流播放延迟以及录像存储

文为原创文章&#xff0c;转载请注明原文出处 本文章博客地址&#xff1a;https://hpzwl.blog.csdn.net/article/details/131679108 红胖子(红模仿)的博文大全&#xff1a;开发技术集合&#xff08;包含Qt实用技术、树莓派、三维、OpenCV、OpenGL、ffmpeg、OSG、单片机、软硬结…

每日一题——反转链表

题目 给定一个单链表的头结点pHead(该头节点是有值的&#xff0c;比如在下图&#xff0c;它的val是1)&#xff0c;长度为n&#xff0c;反转该链表后&#xff0c;返回新链表的表头。 数据范围&#xff1a;0≤n≤1000 要求&#xff1a;空间复杂度 O(1) &#xff0c;时间复杂度 O…

Python实战项目——旅游数据分析(四)

由于有之前的项目&#xff0c;所以今天我们直接开始&#xff0c;不做需求分析&#xff0c;还不会需求分析的可以看我之前的文章。Python实战项目——用户消费行为数据分析&#xff08;三&#xff09; 导入库 import numpy as np import pandas as pd import matplotlib.pyplo…

PHP后台登录功能单账号登录限制

PHP后台登录功能单账号登录限制 单账号登陆是什么第一步创建数据表第二步创建登录页面test2.html第三步创建登录提交test2.php第四步访问后台首页第五步演示 单账号登陆是什么 一个用户只能登录一个账号通常被称为单账号登录限制或单用户单账号限制。这意味着每个用户只能使用…

Linux 学习记录53(ARM篇)

Linux 学习记录53(ARM篇) 本文目录 Linux 学习记录53(ARM篇)一、内存读写指令1. 在C语言中读取内存2. 指令码及功能3. 格式4. 使用示例5. 寻址方式(1. 前索引方式(2. 后索引方式(3. 自动索引 6.批量寄存器操作指令(1. 操作码(2. 格式(3. 使用示例(4. 地址增长方式>1 ia后缀&…

========Java基础——小结1========

一、Java 两大版本 Java 主要分为两个版本: Java SE 和Java EE。 Java SE 全称Java Platform Standard Edition&#xff0c;是 Java 的标准版&#xff0c;主要用于桌面应用程序开发&#xff0c;它包含了 Java 语言基础、JDBC (Java 数据库连接)、I/O (输入/输出)、TCP/IP 网络…

2.8 Android ebpf帮助函数解读(七)

121.long bpf_read_branch_records(struct bpf_perf_event_data *ctx, void *buf, u32 size, u64 flags) 描述:对于附加到 perf 事件的 eBPF 程序,检索与 ctx 关联的分支记录(struct perf_branch_entry),并将其存储在 buf 指向的缓冲区中,最大大小为size字节。 返回值:…