用OC实现一个栈:结合单链表创建动态栈
一、介绍
栈是一种数据存储结构,存储的数据具有先进后出的特点。栈一般分为动态栈和静态栈。
静态栈比较好理解,例如用数组实现的栈。动态栈可以用链表来实现。
方式:固定base指针,每次更改top指向入栈的节点,遍历时从top节点遍历即可。
判空:s.top == s.base && s.top == nil && s.base == nil
栈满:s.top - s.base >= s.stackSize
三、图示

初始状态:s.top = s.base = nil,栈顶和栈底指针指向空,分配栈大小为s.stackSize = 4;
入栈状态:s.base不变,s.top = node,栈底指针不变,栈顶指针指向新节点
栈满状态:s.top - s.base >= s.stackSize, 遍历链表,链表的长度等于或大于栈大小
出栈状态:s.base不变,s.top = node->next, node节点从链表断裂取出,top指针指向node下一个节点
栈空状态:s.top=nil,并将s.base=s.stop。
三、代码
node:
// Node.h
// 运行时
//
// Created by 夏远全 on 2019/10/16.
// #import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface Node : NSObject
@property (nonatomic, assign) int data;
@property (nonatomic, strong, nullable) Node *next;
-(instancetype)initWithData:(int)data;
@end NS_ASSUME_NONNULL_END
// Node.m
// 运行时
//
// Created by 夏远全 on 2019/10/16. #import "Node.h" @implementation Node -(instancetype)initWithData:(int)data {
self = [super init];
if (self) {
self.data = data;
self.next = nil;
}
return self;
} @end
stack:
//
// Stack.h
// 运行时
//
// Created by 夏远全 on 2019/10/16.
// #import <Foundation/Foundation.h>
#import "Node.h" NS_ASSUME_NONNULL_BEGIN /*
特点:栈是先进后出的特点,采用链表实现一个动态栈(静态栈可以用数组实现)。固定base指针,每次更改top指向入栈的节点,遍历时从top节点遍历即可。 链表栈
判空:s.top == s.base && s.top == nil && s.base == nil
栈满:s.top - s.base >= s.stackSize
*/ @interface Stack : NSObject /**
构造一个栈
@return 栈
*/
+(instancetype)constructStack; /**
推入一个节点
@param node 节点
*/
-(void)pushNode:(Node *)node; /**
推出一个节点
*/
-(void)pop; @end NS_ASSUME_NONNULL_END
//
// Stack.m
// 运行时
//
// Created by 夏远全 on 2019/10/16.
// #import "Stack.h" @interface Stack ()
@property (nonatomic, strong) Node *top; //栈顶指针
@property (nonatomic, strong) Node *base; //栈底指针
@property (nonatomic, assign) int stackSize; //栈初始大小
@end @implementation Stack +(instancetype)constructStack
{
Stack *stack = [[Stack alloc] init];
stack.top = stack.base;
stack.stackSize = ;
return stack;
} -(void)pushNode:(Node *)node { //空节点
if (!node) {
NSLog(@"------不能push一个空的节点-------");
return;
} //栈满
if ([self isFull]) {
NSLog(@"------栈已满-------,当前节点node值: %d不能被push", node.data);
[self printStack];
return;
} //修改栈顶指针,确定栈底指针,不会再改变
if ([self isEmpty]) {
self.top = self.base = node;
}
else{
node.next = self.top;
self.top = node;
}
NSLog(@"push入栈的节点:data = %d", node.data);
} -(void)pop { //栈为空
if ([self isEmpty]) {
NSLog(@"------栈已空-------");
return;
} //删除节点,并修改栈顶指针
Node *popNode = self.top;
self.top = popNode.next;
NSLog(@"pop出栈的节点:data = %d",popNode.data); //节点pop完毕
if (self.top == nil) {
self.base = self.top;
NSLog(@"------栈已空-------");
}
} -(BOOL)isEmpty {
return (self.top == self.base && self.top == nil && self.base == nil);
} -(BOOL)isFull { //遍历长度
int size = ;
Node *p = self.top;
while (p != nil) {
size ++;
p = p.next;
}
return size >= self.stackSize;
} -(void)printStack { NSMutableArray *nodes = [NSMutableArray array];
Node *p = self.top;
while (p != nil) {
[nodes addObject:@(p.data)];
p = p.next;
}
NSLog(@"当前栈的所有节点为:%@",[nodes componentsJoinedByString:@"->"]);
} @end
四、打印
-(void)test_DataStructure_Stack {
/// 构造栈
Stack *stack = [Stack constructStack];
/// 构造元素
Node *node1 = [[Node alloc] initWithData:];
Node *node2 = [[Node alloc] initWithData:];
Node *node3 = [[Node alloc] initWithData:];
Node *node4 = [[Node alloc] initWithData:];
Node *node5 = [[Node alloc] initWithData:];
Node *node6 = [[Node alloc] initWithData:];
/// push时,进去的顺序为: 1、2、3、4、5
[stack pushNode:node1];
[stack pushNode:node2];
[stack pushNode:node3];
[stack pushNode:node4];
[stack pushNode:node5];
[stack pushNode:node6];//node6不能被push进去,栈已满
/// pop时,出来的顺序为: 5、4、3、2、1
[stack pop];
[stack pop];
[stack pop];
[stack pop];
[stack pop];//最后一个节点被pop出来,栈已空
}
-- ::03.214331+ 运行时[:] push入栈的节点:data =
-- ::03.214513+ 运行时[:] push入栈的节点:data =
-- ::03.214620+ 运行时[:] push入栈的节点:data =
-- ::03.214715+ 运行时[:] push入栈的节点:data =
-- ::03.214796+ 运行时[:] push入栈的节点:data =
-- ::03.214878+ 运行时[:] ------栈已满-------,当前节点node值: 6不能被push
-- ::03.215023+ 运行时[:] 当前栈的所有节点为:->->->->
-- ::03.215111+ 运行时[:] pop出栈的节点:data =
-- ::03.215208+ 运行时[:] pop出栈的节点:data =
-- ::03.215508+ 运行时[:] pop出栈的节点:data =
-- ::03.215845+ 运行时[:] pop出栈的节点:data =
-- ::03.216101+ 运行时[:] pop出栈的节点:data =
-- ::03.216429+ 运行时[:] ------栈已空-------
用OC实现一个栈:结合单链表创建动态栈的更多相关文章
- python中栈的单链表实现
参考博客:https://www.cnblogs.com/stacklike/p/8284550.html 基于列表的简单实现 # 先进后出 # 以列表实现的简单栈 class SimpleStack ...
- C语言 - 栈和单链表的实现
单链表:linkList.h linkList.c #ifndef LINKLIST_H_INCLUDE #define LINKLIST_H_INCLUDE #include <Windows ...
- 线性表:实现单链表和子类栈(Stack)及单向队列(Queue) [C++]
刚刚开始学习c++.之前c的内容掌握的也不多,基本只是一本概论课的程度,以前使用c的struct写过的链表.用python写过简单的数据结构,就试着把两者用c++写出来,也是对c++的class,以及 ...
- java实现一个简单的单链表反转
自定义一个单链表,实现链表反转: 1.普通方法实现 2.递归方式实现 package listNode; public class ReverseNode { public static void m ...
- 单链表创建、删除、查找、插入之C语言实现
本文将详细的介绍C语言单链表的创建.删除.查找.插入以及输出功能 一.创建 #include<stdio.h> #include<stdlib.h> typedef int E ...
- Javascript - 栈 和 单链表
最近在重温数据结构,于是写了一些代码玩玩,都是很初级的,表喷各位.... function Stack() { this.dataStore = []; this.top = 0; } Stack.p ...
- 数据结构与算法——链表 Linked List(单链表、双向链表、单向环形链表-Josephu 问题)
链表是有序的列表,但是在内存中存储图下图所示 链表是以 节点 的方式来存储,是 链式存储 每个节点包含 data 域.next 域,指向下一个节点 链表的各个节点 不一定是连续存储,如上图所示 链表还 ...
- C++ "链链"不忘@必有回响之单链表
1. 前言 数组和链表是数据结构的基石,是逻辑上可描述.物理结构真实存在的具体数据结构.其它的数据结构往往在此基础上赋予不同的数据操作语义,如栈先进后出,队列先进先出-- 数组中的所有数据存储在一片连 ...
- C++实现简单的单链表
下面实现的是一个简单的单链表 功能不多,学习使用 #pragma once #include <iostream> using namespace std; class ListEx { ...
随机推荐
- 短信相关的AT指令以及信令
本文链接:https://blog.csdn.net/sjz4860402/article/details/78552756 此次的短信AT指令和信令从以下几个方面介绍: 一 . 短信AT指令的格式二 ...
- 一条简单的更新语句,MySQL是如何加锁的?
看如下一条sql语句: # table T (id )) delete : MySQL在执行的过程中,是如何加锁呢? 在看下面这条语句: : 那这条语句呢?其实这其中包含太多知识点了.要回答这两个问题 ...
- Python 获取MD5加密值
Python 获取MD5加密值方法封装 import hashlib def get_md5(s): """获取MD5加密值 :param s: 需要加密的字符串 :re ...
- 服务器性能测试实时监控Linux命令
实时监控 top -h : 查看帮助 -p : 监控指定进程,当监控多个进程时,进程ID以逗号隔开,这个选项只能在命令行下使用 top 任务区命令 M: 按内存使用率排序(大写) P:按CPU使用率排 ...
- LNMP(5)
目录 一.实战 1.安装 安装nginx 数据库 php wordpress 2.三者建立联系 nginx和php建立联系 php与mariadb建立关系 二.数据分离 三.理论 静态和动态 web应 ...
- 进制转换器V1.0_Beta
一.截图部分 二.代码部分: char2num() 作用:将字符转化成对应的数字 e.g. '9'->9 'A'->10 int char2num(char ch) ...
- TKinter当Label绑定bind事件时传参方法
记录下tkinter的 当在label绑定bind事件时,遇到需要传参时的解决方法(因为有event存在 所以不能直接传参) https://www.cnblogs.com/liyuanhong/ar ...
- ESP8266源码分析--打印的基本用法
缘由: 物联网小芯片中,很多都不是特别复杂,绝大多数问题都需要靠串口打印就能定位的.所以,串口打印是一个非常靠谱的玩意.一定要好好的利用.ESP8266的打印模板设计的特别好,这里我就列出来,供大家参 ...
- oracle 中 insert select 和 select insert 配合使用
Insert Into select 与 Select Into 哪个更快? 在平常数据库操作的时候,我们有时候会遇到表之间数据复制的情况,可能会用到INSERT INTO SELECT 或者 SEL ...
- Java生鲜电商平台-SpringCloud分布式请求跟踪系统设计与实践
Java生鲜电商平台-SpringCloud分布式请求跟踪系统设计与实践 Java生鲜电商平台微服务现状 某个服务挂了,导致上游大量报警,如何快速定位哪个服务出问题? 某个核心挂了,导致大量报错,如何 ...