基于双向链表实现的栈

看了LinkedList的源码,明白了LinkedList底层使用的是双向链表,一直想找个机会实现一下双向链表,今天写到力扣的每日一题20.有效的括号,正好此题需要使用到栈,所以借此机会来自己实现一下基于双向链表实现的栈,实现栈之前要了解以下知识

1.什么是双向链表

双向链表是指一个节点有一个数据域,两个指针域,一个指针域指向上一个节点,一个指针域指向下一个节点,现在将指向上一个节点的指针域命名为pre,将指向下一个节点的指针域命名为next,节点命名为node,一个合格的双向链表如下图所示
在这里插入图片描述
中间的node可以是多个,为了方便只画了一个

2.什么是栈

栈(stack)又名堆栈,它是一种运算受限的线性表。限定仅在表尾进行插入和删除操作的线性表。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素。
在我实现的栈中,定义push()方法为向栈顶中加入一个元素,pop()方法为删除栈顶元素,top()方法为得到栈顶元素,isEmpty()为判断栈是否为空

3.实现基于双向链表的栈的步骤

根据上面的图片

  • 第一步
    首先需要创建一个Node类,里面有参数data,和两个Node pre和next

  • 第二步
    创建双向链表类了,很显然双向链表中有两个属性,first和last用来保存头节点和尾节点

  • 第三步
    push()方法,向尾部添加一个元素如何实现,先用一张图来假设我们新加入的节点和last节点的关系
    在这里插入图片描述
    初始时,两个节点没有任何关系,只需参考合格的双向链表那张图片连线就好
    在这里插入图片描述

第一步可以将last的next指针域指向node
在这里插入图片描述
显然,第二步为将node的pre指针域指向last
在这里插入图片描述

最后,不要忘记更新last的位置

  • 第四步
    pop()方法的实现,删除尾部元素,这个操作
    明显一句话就能实现,last=last.pre

top和isEmpty方法也是很容易,直接在代码中解释

4.基于双向链表实现的栈代码

Node类

class Node<E> {
	public E data;
	public Node<E> next;
	public Node<E> pre;

	public Node(E data, Node<E> next, Node<E> pre) {
		super();
		this.data = data;
		this.next = next;
		this.pre = pre;
	}

}

Link类

class Link<E> {
	Node<E> first, last;

	/**
	 * 向栈的尾部添加节点,数据域为data
	 * 
	 * @param data
	 */
	public void push(E data) {
		if (first == null) {// 如果栈为空,直接赋值
			first = last = new Node<E>(data, null, null);
		} else {
			Node<E> node = new Node<E>(data, null, last);// 将node的pre域指向last
			last.next = node;// last的next域指向node
			last = node;// 更新last
		}
	}

	/**
	 * 删除尾部节点
	 * 
	 * @return 删除的节点的数据域的值
	 */
	public E pop() {
		E data;
		if (last == first) {// 如果last和first都指向同一个元素,显然栈中只有一个元素了,直接赋值为空
			data = last.data;
			last = first = null;
		} else {
			data = last.data;
			last = last.pre;// last向前移动一位
			last.next = null;
		}
		return data;
	}

	/**
	 * 得到栈顶元素,也就是尾巴的数据域
	 * 
	 * @return 数据域的值
	 */
	public E top() {
		return last.data;
	}

	/**
	 * 判断栈是的为空
	 * 
	 * @return true表示为空,false表示不为空
	 */
	public boolean isEmpty() {
		return first == null;
	}

}

5.力扣题目的解答

只要左括号进栈,右括号判断栈顶左括号是否与之匹配就好,其他情况全部返回false,最后判断栈是否为空,为空证明匹配,否则不匹配

public boolean isValid(String s) {
		if (s == null) {
			return true;
		}
		if (s.length() == 0) {
			return true;
		}
		Link<Character> stack = new Link<Character>();
		int len = s.length();
		for (int i = 0; i < len; i++) {
			char ch = s.charAt(i);
			if (ch == '(' || ch == '[' || ch == '{') {
				stack.push(ch);
			} else {
				if (stack.isEmpty()) {
					return false;
				}
				char top = stack.top();
				if (top == '(' && ch == ')') {
					stack.pop();
				} else if (top == '[' && ch == ']') {
					stack.pop();
				} else if (top == '{' && ch == '}') {
					stack.pop();
				} else {
					return false;
				}
			}

		}
		return stack.isEmpty();
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值