数据结构---栈

栈是一种后进先出的结构

通常有两种实现方式

1.静态数组或者动态数组的实现方式

2.链表的实现方式。

运用到栈的算法有哪些呢:括号匹配问题,中缀表达式转后缀表达式问题,迷宫路径搜索问题,非递归遍历问题,回溯搜索问题,递归转非递归。


1.栈的实现

1.1 java数组实现

/*
 * 用java数组实现简单的栈
 * */
public class StackX {
	private int maxSize;
	private Object[] stackArray;
	private int top;

	public StackX(int s) {
		maxSize = s;
		stackArray = new Object[maxSize];
		top = -1;
	}

	// 入栈
	public void push(Object i) {
		if (top != maxSize - 1) {
			stackArray[++top] = i;
		}
	}

	// 出栈
	public Object pop() {
		if (top != -1) {
			return stackArray[top--];
		} else {
			return 0;
		}
	}

	// 查看栈顶元素
	public Object peek() {
		return stackArray[top];
	}

	// 判断栈是否为空
	public boolean isEmpty() {
		return top == -1;
	}

}

入栈操作数组不够时可考虑数组扩容

	// 数组容量的扩容,当空间(.length)不够的时候,增加1.5倍
	private static int[] arrycopy(int[] ss) {
		int[] copy = new int[ss.length * 3 / 2];
		System.arraycopy(ss, 0, copy, 0, ss.length);
		return copy;
	}


1.2 c++数组实现

#define DataType int  
#define MAX 1024  

typedef struct  
{  
    DataType data[MAX];  
    int top;  
}stack, *pstack;  

pstack *init_stack()  
{  
    pstack ps;  
    ps=(pstack)malloc(sizeof(stack));  
    if(!ps)  
    {  
        printf("Error. fail malloc.../n");  
        return NULL;  
    }  
    ps->top=-1;  
    return ps;  
}  

int empty_stack(pstack ps)  
{  
    if(-1 == ps->top)  
        return 1;  
    else  
        return 0;  
}  

int push(pstack ps, DataType data)  
{  
    if(ps->top == MAX-1)  
    {  
        printf("Stack is full.../n");  
        return 0;  
    }  
    ps->top++;  
    ps->data[ps->top]=data;  
    return 1;  
}  

int pop(pstack ps, DataType *data)  
{  
    if(empty_stack(ps))  
    {  
        printf("Stack is empty.../n");  
        return 0;  
    }  
    *data=ps->data[ps->top];  
    ps->top--;  
    return 1;  
} 


2.关于栈的算法

2.1十进制转二进制

	/**
	 * 利用堆栈后进先出的效果 写十进制转二进制 如果转八进制 就把2换成8
	 * 
	 * @param i
	 */
	private static void binary(int i) {
		String str = "";
		Stack s = new Stack();
		while (i > 0) {
			s.push(i % 2);
			i = i / 2;
		}
		while (!s.isEmpty()) {
			str += s.pop();
		}
		System.out.println(str);
	}

}

2.2用两个栈实现一个队列(剑指Offer-7)

思路:
  假设两个栈A和B,且都为空。
  可以认为栈 A为提供入队列的功能,栈B提供出队列的功能。
  入队列:入栈A 
  出队列:
  1 如果栈B不为空,直接弹出栈B的数据。
  2 如果栈 B为空,则依次弹出栈A的数据,放入栈B中(栈B占空间比栈A要大),再弹出栈B的数据。

public class stackImQueue {

	// s1:实现入队,s2:实现出队
	private Stack<Object> s1;
	private Stack<Object> s2;
	
	stackImQueue(){
		s1=new Stack<Object>();
		s2=new Stack<Object>();
	}

	// 入队
	public void enQueue(Object obj) {
		s1.push(obj);
	}

	// 出队
	public Object DeQueue() {
		Object obj;
		if (s2.isEmpty()) {
			while (!s1.isEmpty()) {
				obj = s1.pop();
				s2.push(obj);
			}
		}
		return s2.pop();
	}

	// 判断队列是否为空
	public boolean isEmpty() {
		if (s1.isEmpty() && s2.isEmpty())
			return true;
		return false;
	}

}

2.3包含min方法的栈(剑指Offer-21)

题目:定义栈的数据结构,要求添加一个min函数,能够得到栈的最小元素。要求函数min、push以及pop的时间复杂度都是O(1)。

方法一:

题目要求的栈A,用来记录最小值的栈B。

push:栈A直接push新元素data。data与B栈中的栈顶元素比较,如果新值较小,则在B栈中push新值;否则再次pushB栈顶元素到B栈。

pop:栈Apop,栈B也跟着pop。

public class MinStack {

	private Stack<Integer> stack;
	private Stack<Integer> minStack;

	public MinStack() {
		stack = new Stack<Integer>();
		minStack = new Stack<Integer>();
	}

	// 入栈
	public void push(int i) {
		stack.push(i);
		if (minStack.isEmpty() || i <= minStack.peek()) {
			minStack.push(i);
		}else{
			minStack.push(minStack.peek());
		}
	}

	// 出栈
	public int pop() {
		int popNum;
		if (stack.isEmpty()||minStack.isEmpty()) {
			return 0;
		} 
		popNum = stack.pop();
		minStack.pop();
		return popNum;
	}

	//返回栈中最小值
	public int minNum(){
		if (stack.isEmpty()||minStack.isEmpty()) {
			return 0;
		} 
		return minStack.peek();
	}

}

方法二:

常规解空间上的一个优化:一般说来,最小值不会每次都需要更新,因此最小值栈里面会有很多重复元素。

题目要求的栈A,用来记录最小值的栈B。

push:栈A直接push新元素data。当data<=原最小值(即是B.top)B栈中push新值data;注意这个==的条件是不可少的,这是为了防止在pop的时候错误的pop最小值。

pop:栈A pop,当A.pop==B.top时,栈B pop。其他时候不对栈B进行pop。

只需对上面代码的push、pop做修改

	// 入栈
	public void push(int i) {
		stack.push(i);
		if (minStack.isEmpty() || i <= minStack.peek()) {
			minStack.push(i);
		}
	}

	// 出栈
	public int pop() {
		int popNum;
		if (stack.isEmpty() || minStack.isEmpty()) {
			return 0;
		}
		popNum = stack.pop();
		if (popNum == minStack.peek())
			minStack.pop();
		return popNum;
	}

方法三:

只需要额外开一个用于存放当前最小值的变量min即可.因此下面提到的push和pop操作都是对于题目中要求的栈来操作的,当然,这也是这个算法里唯一的栈.

设push的参数为v_push,pop的返回值为v_pop。
push:首先push (v_push-min),如果v_push < min,更新min为v_push.
pop:(栈顶元素为top)
     如果top >= 0, v_pop = min+top;
     如果top < 0, v_pop = min,然后更新min为min-top.
min函数:只需要返回min空间的内容即可.

public class MinStack {

	private Stack<Integer> stack;
	private int min;

	public MinStack() {
		stack = new Stack<Integer>();
	}

	// 入栈
	public void push(int v_push) {
		if (stack.isEmpty()) {
			min = v_push;
		}
		stack.push(v_push - min);
		if (v_push < min) {
			min = v_push;
		}
	}

	// 出栈
	public int pop() {
		int v_pop;
		int top = stack.pop();
		if (top >= 0) {
			v_pop = min + top;
		} else {
			v_pop = min;
			min = min - top;
		}
		return v_pop;
	}

	// 返回栈中最小值
	public int minNum() {
		return min;
	}

	// 判断栈空
	public boolean isEmpty() {
		if (stack.isEmpty())
			return true;
		return false;
	}

}

2.4 打印堆栈

在不破坏栈结构的情况下打印堆栈,只允许用push、pop操作

	// 打印堆栈
	public void printStack(Stack<Integer> s) {
		if (isEmpty())
			return;
		int top = (int) s.peek();
		System.out.println(top + " ");
		s.pop();
		printStack(s);
		s.push(top);
	}


2.5 栈的压入、弹出序列(剑指Offer-22)

题目:输入两个整数序列。其中一个序列表示栈的push顺序,判断另一个序列有没有可能是对应的pop顺序。为了简单起见,我们假设push序列的任意两个整数都是不相等的。
比如输入的push序列是1、2、3、4、5,那么4、5、3、2、1就有可能是一个pop系列。因为可以有如下的push和pop序列:push 1,push 2,push 3,push 4,pop,push 5,pop,pop,pop,pop,这样得到的pop序列就是4、5、3、2、1。但序列4、3、5、1、2就不可能是push序列1、2、3、4、5的pop序列。

解析:这道题的一个很直观的想法就是建立一个辅助栈,每次push的时候就把一个整数push进入这个辅助栈,同样需要pop的时候就把该栈的栈顶整数pop出来。

public static void main(String[] args) {
		int[] push = { 1, 2, 3, 4, 5 };
		int[] pop = { 4, 5, 3, 2, 1 };
		System.out.print("输出序列是否为合法的pop序列:" + IsPossiblePopOrder(push, pop));

	}

	public static boolean IsPossiblePopOrder(int[] push, int[] pop) {

		if (push.length != pop.length) {
			System.out.println("输入输出序列长度不一样!");
			return false;
		}
		int length = push.length;
		boolean isPossible = false;

		Stack<Integer> list = new Stack<Integer>();
		int pushindex = 0;
		int popindex = 0;
		if (push != null && pop != null && length > 0) {
			// 检查pop序列中每一个字符
			while (popindex < length) {
				// 当栈顶字符和pop中要访问的字符不一样时候,将push中未入栈的字符入栈
				while (list.size() == 0 || list.peek() != pop[popindex]) {
					if (pushindex >= length)
						break;
					list.add(push[pushindex]);
					pushindex++;

				}
				// 入栈完毕后,如果栈顶元素和pop中要访问的字符仍然不一样,则此pop序列不是合法的pop序列
				if (list.peek() != pop[popindex]) {
					break;
				}
				// 检查pop序列中的下一个字符
				list.pop();
				popindex++;
			}
			// 如果pop序列中所有的字符都被检查过,则该序列是合法的
			if (list.size() == 0 && popindex == length) {
				isPossible = true;
			}
		}
		return isPossible;

	}






  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值