数据结构入门(四)-栈的定义与实现

来源:互联网 发布:c语言编程软件手机版 编辑:程序博客网 时间:2024/05/18 20:49

1.栈的定义

(stack)是限定仅在标尾进行插入和删除操作的线性表。
我们把允许插入和删除的一端称为栈顶,另一端称为栈底,不含任何数据元素的栈称为空栈。栈又称为后进后出(Last In First Out)的线性表简称==LIFO==结构

很多软件比如 Word,Photoshop等文档或图像编辑软件中都有撤销(undo)的操作,也就是用栈的方式来实现的。

的插入操作,叫做进栈,也称压栈,入栈。
的删除操作,叫做出栈,也有的叫做弹栈。

进栈出栈的变化形式

  • 1,2,3 进 =》 3,2,1出
  • 1进,1出;2进,2出,3进,3出
  • 1进,2进,2出,1出,3进,3出
  • 1进,1出,2进,3进,3出,2出
  • 1进,2进,2出,3进,3出,1出

栈的抽象数据类型

InitStack(*S):初始化操作,建立一个空栈DestoryStack(*S):弱栈存在,销毁栈ClearStack(*S):将栈清空StackEmpty(S):若栈为空,返回True,否则返回falseGetTop(S,*e):弱栈存在且为非空,用e返回S的栈顶元素  Push(*S,e):若栈S存在,插入新元素e到栈S中并成为栈底元素Pop(*S,*e):删除栈S中栈顶元素,并用e返回元素StackLength(S):返回栈S的元素个数  

栈的顺序存储结构及实现

栈的顺序存储结构

下标为0的一端作为栈底,因为首元素都存在栈底,因为首元素都存在栈底,变化小,所以让它作栈底。若存储栈的长度为StackSize,则栈顶位置top必须小于StackSize.当栈存在一个元素是,top等于0,因此常用-1判定条件为top等于-1

对栈操作

Java 中使用LinkedList来模拟栈的操作其中提供了以下方法

addFirst
removeFirst();
addLast();
removeLast();
在栈中,push为入栈操作,pop为出栈操作。
Push用addFirst(),pop用removeFirst(),实现后进先出
用isEmpty() 其父类的方法,判断栈是否为空
用Java来实现栈

    public class MyStack{ //定义一个栈类        int[] array; //用int数组来保存数据,根据需要可以更换类型        int s_size; //定义一个游标。    public  MyStack(int i){ //定义一个带参数构造器        array=new int[i] //动态定义数组的长度        s_size=0 //默认游标为0    }    public MyStack(){ //定义一个默认构造器            this(50); //调用带参数构造器,默认长度为50    }    public void push(int i) { //定义压栈方法        arrly[this.s_size]=i;// 将传进去的参数存储到数组中        this.s_size++; //将游标自增    }    public int pop(){ //定义弹栈方法,从栈顶取出元素        if(this.s_size!=0){            int t = array[s_size-1] //用中间变量保存栈顶的元素            array[s_size-1]=0 //取完元素将该位置设为0            s_size--; //将游标递减            return t; 返回取出的栈顶元素        }else{            System.out.println("The Stack is Empty");            return 0;        }    public boolean isEmpthy(){ //判断栈是否为空        return this.s_size==0;    }    public void printALL{ //打印出栈中所有元素,不是取出        if(!this.isEmpty){            for(int i=this.s_size-1,i>=0,i--){                System.out.println(array[i])            }        }    }}

两栈共享空间

数组有两个端点,两个栈有两个栈底,让一个栈的栈底为数组的始端,即下标为0处,另一个栈为数组的末端,即下标为数组长度n-1处。这样,两个栈如果增加元素,就是两端点向中间延伸。

image

/** * Created by gyg on 2017/2/9. * 此类用于模拟两栈共享空间的java实现。 */public class TwoStackShareSpace<T> {    private Object[] element; //存放元素的数组    private int stackSize; //定义栈的大小    private int top1; // 定义栈1的栈顶指针    private int top2;// 定义栈2的栈顶指针    /**     * 初始化栈     */    public TwoStackShareSpace(int size){        element = new Object[size]; //带参数的构造函数,创建指定大小的数组        stackSize = size; //给栈的大小赋值        top1 = -1; // 定义栈1的栈顶指针,默认为空时为 -1        top2 = size;// 定义栈2的栈顶指针,默认为size的大小。    }    /**     * 压栈,即在栈中存储数据     *@param i 第几个栈     *@param o 入栈元素     */    public boolean push(int i,Object o){        if(top1+1 == top2){ // 用来判断栈是否已经被栈满的判定条件            throw new RuntimeException("栈满");        }        else if(i ==1 ){ //i等于1时表示在第一个栈中插入元素            top1++; //  top1这时为-1 ++后为0            element[top1]=o; // 数组中在小标为0的位置加入元素        }else if(i ==2 ){ //i等于2时表示在第二个栈中插入元素            top2--; //top2这时位size的大小,            element[top2]=o; //将在第二个栈的栈顶添加元素        }        else{            throw new RuntimeException("输入错误");        }        return true;    }    /**     * 出栈     * @param i 第几个栈     * @return     *///    @SuppressWarnings("unchecked")    public T pop (int i ){        if(i==1){            if(top1==-1)                throw new RuntimeException("栈1为空");            element[top1]=0; //将弹出的栈元素位置置0;            return (T)element[top1--]; //返回弹出的元素。        }        else if(i ==2){            if(top2==stackSize)                throw new RuntimeException("栈2为空");            element[top2]=0; //将弹出的栈元素置0;            return (T)element[top2++]; //返回要弹出的元素        }else            throw new RuntimeException("输入错误");    }    /**     * 获取栈顶元素     * @param i     * @return     */    public T get(int i){        if(i == 1){            if(top1 == -1)                throw new RuntimeException("栈1为空");            return (T)element[top1];        }else if(i==2){            if(top2 == stackSize)                throw new RuntimeException("栈2为空");            return (T)element[top2];        }else            throw new RuntimeException("输入错误");    }    /**     * 判断栈是否为空     * @param i     * @return     */    public boolean ifEmpty(int i){        if(i == 1){            if(top1 == -1) //判断栈1是否为空                return true;            else                return false;        }else if(i == 2){            if(top2==stackSize) //判断栈二是否为空                return true;            else                return false;        }else            throw new RuntimeException("输入错误");    }    /**     * 遍历结果     */    public String toString(){        String str1 = "栈1:[";        String str2 = "栈2: [";        for(int i=top1;i>=0;i--){            if(i==0)                str1 =str1+(T)element[i];            else                str1=str1+(T)element[i]+",";        }        str1+="]";        for(int i=top2;i<stackSize;i++){            if(i == stackSize-1)                str2 = str2+(T)element[i];            else                str2=str2+(T)element[i]+",";        }        str2+="]";        return str1+"\n\r"+str2;    }    public static void main(String args[])    {        TwoStackShareSpace tsss = new TwoStackShareSpace(20); //初始化一个栈长度为20;        System.out.println("第一个栈:"+tsss.ifEmpty(1)+" : 第二个栈:"+tsss.ifEmpty(2));        tsss.push(1,"张三"); //压栈,在第一个栈中添加元素"张三"        tsss.push(1,3); // 压栈,元素加在栈顶        tsss.push(1,"李四");//压栈,元素加在栈顶        tsss.pop(1); //弹栈        tsss.push(2,2); //压栈,在第二个栈中添加元素2        System.out.println(tsss.toString());//遍历输出栈栈中元素        System.out.println("第一个栈:"+tsss.ifEmpty(1)+" : 第二个栈:"+tsss.ifEmpty(2));    }}

栈的链式存储结构及实现

栈的链式存储结构,简称为链栈。
把栈顶放在单链表的头部,另外,都已经有了栈顶在头部了,单链表中的头结点也就失去了意义,通常对于链栈,是不需要头结点的。

对链栈的操作

链栈的进栈push和出栈pop操作都很简单,没有任何循环操作,时间复杂度均为0(1),如果栈的使用过程中元素变化不可预料,有时很小,有时非常大,那么最好是用链栈,反之,如果它的变化在可控范围内,建议使用顺序栈更好一些。
image

http://blog.csdn.net/bruce_6/article/details/25125751

栈的应用-递归

递归定义:我们把一个直接调用自己通过一系列的调用语句间接地调用自己的函数,称作递归函数

菲波那切数列实现

1 1 2 3 5 8 13 21 34 55 89 144 .....表中数字构成了一个数列。这个数列有个十分明显的特点:前面相邻两项之和构成了后一项。public class Fbi{    public void demo(int i)    {        if(i<2){            return i==0?0:1;        }        return demo(i-1)+demo(i-2);//这里使用递归,调用自己。    }    public static void main(String[] args){        int i;        for(int i=0;i<40;i++)        System.out.println(demo(i))    }}

栈的应用-四则运算表达式求值

一种不需要括号的后缀表达式,我们也把它称为逆波兰表示。

对于 “9+(3-1)* 3+10/2”用后缀表达式为 “9 3 1 - 3 * + 10 2 / + ”规则:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号就将处于栈顶的两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果  

中缀表达式转后缀表达式

我们把平时所用的标准四则运算表达式,即“9+(3-1)*3+10/2”叫做中缀表达式。

中缀表达式“9+(3-1)*3+10/2"转化为后缀表达式“9 3 1 - 3 * + 10 2 / + ”规则:从左到右遍历中缀表达式的每个数字和符号,若是数字就输出,即成为后缀表达式的一部分;  若是符号,则判断其与栈顶符号的优先级,是右括号或优先级不高于栈顶符号则栈顶元素一次出栈并输出,并将当前符号进栈,一直到最终输出后缀表达式为止
0 0
原创粉丝点击