• 用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 = 5;
        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 = 0;
        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:1];
        Node *node2 = [[Node alloc] initWithData:2];
        Node *node3 = [[Node alloc] initWithData:3];
        Node *node4 = [[Node alloc] initWithData:4];
        Node *node5 = [[Node alloc] initWithData:5];
        Node *node6 = [[Node alloc] initWithData:6];
        
        /// 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出来,栈已空
    }
    2019-10-16 15:05:03.214331+0800 运行时[29420:1007559] push入栈的节点:data = 1
    2019-10-16 15:05:03.214513+0800 运行时[29420:1007559] push入栈的节点:data = 2
    2019-10-16 15:05:03.214620+0800 运行时[29420:1007559] push入栈的节点:data = 3
    2019-10-16 15:05:03.214715+0800 运行时[29420:1007559] push入栈的节点:data = 4
    2019-10-16 15:05:03.214796+0800 运行时[29420:1007559] push入栈的节点:data = 5
    2019-10-16 15:05:03.214878+0800 运行时[29420:1007559] ------栈已满-------,当前节点node值: 6不能被push
    2019-10-16 15:05:03.215023+0800 运行时[29420:1007559] 当前栈的所有节点为:5->4->3->2->1
    2019-10-16 15:05:03.215111+0800 运行时[29420:1007559] pop出栈的节点:data = 5
    2019-10-16 15:05:03.215208+0800 运行时[29420:1007559] pop出栈的节点:data = 4
    2019-10-16 15:05:03.215508+0800 运行时[29420:1007559] pop出栈的节点:data = 3
    2019-10-16 15:05:03.215845+0800 运行时[29420:1007559] pop出栈的节点:data = 2
    2019-10-16 15:05:03.216101+0800 运行时[29420:1007559] pop出栈的节点:data = 1
    2019-10-16 15:05:03.216429+0800 运行时[29420:1007559] ------栈已空-------

     

  • 相关阅读:
    CSS3新增文本属性实现图片点击切换效果
    swipe和swiper的区别
    uncaught syntaxerror: unexpected token
    科协前辈的阿里面试经验转载1
    Oracle 分析函数
    Jakarta Commons HttpClient 学习笔记 (二)
    Ubuntu eclipse下android virtual device manager不能删除AVD
    Android的界面设计工具——DroidDraw
    JS异步请求数据
    Ubuntu配置JDK和Android环境变量
  • 原文地址:https://www.cnblogs.com/XYQ-208910/p/11685617.html
Copyright © 2020-2023  润新知