算法:栈
2015-11-09 10:03
190 查看
定义:
栈是一种数据结构,一种只能在一端进行插入和删除操作的特殊线性表。它按照先进后出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈 顶,需要读数据的时候从栈顶开始弹出数据(最后一个数据被第一个读出来)。 当你用浏览器浏览网页时,点击一个超链接,浏览器会显示一个新的页面(并将它压入一个栈)。你可以不断点击超链接并访问新页面,但总是可以通 过点击“回退”按钮重新访问以前的页面(从栈中弹出)。这是一个使用栈的实例。
实现
链表是一种递归的数据结构,它或者为空(null),或者是指向一个结点(node)的引用,该结点含有一个泛型的元素和一个指向另一条链表的引用。
结点的实现
在Java中可以使用一个嵌套类来定义结点的抽象数据结构。
private class Node { Item item; Node next; }
一个Node对象含有两个实例变量,类型分别为Item(参数类型)和Node。
构造链表
根据递归定义,我们只需要一个Node类型的变量就能表示一条链表,只要保证它的值是null或者指向另一个Node对象且该对象的next域指向了另一条链表即可。例如,要构造一条含有元素to、be和or的链表,我们首先为每一个元素创造一个结点:
Node first = new Node(); Node second = new Node(); Node third = new Node();
并将每个节点的item域设为所需的值(这里设Item为String):
first.item = “to”; second.item = “be”; third.item = “or”;
然后设置next域来构造链表:
First.next = second; Second.next = third; Third.next = null;
实现插入删除结点
栈只能在一端进行插入和删除操作,同时具有先进后出的原则,所以这里我们只在链表的头部进行插入和删除结点的操作。
在表头插入结点
以上面的例子在表头进行插入结点的操作,要在首结点为first的开头插入字符串not。首先将first保存在oldfirst中,然后将一个新的结点赋予first,并将它的item域设为not, next域设为oldfirst。
在表头删除结点
在表头删除一条链表的首结点,只需将first指向first.next即可。
实现可迭代
在许多应用场景里,用例的要求只是用某种方式处理集合中的每个元素,或者叫做迭代访问集合中的所有元素。有了这种模式,我们能够写出清晰简洁的代码且不依赖于集合类型的具体实现。例如:对于一个String类型的栈stack:Stack<String> stack = new Stack<String>();如果结合是可迭代的,用例用一行语句即可打印出交易的列表: ' for(String s:stack) { System.out.println(s); } ' 这种语法叫做foreach语句:可以将for语句看做对于集合中的每个String数据s,执行以下代码段。这段用例代码不需要知道集合的表示或实现的任何细节,它只想逐个处理集合中的元素。Foreach语句只是while语句的一种简写方式,它本质上和以下while语句是等价的: ' Iterator<String> i = collection.iterator(); while(i.hasNext()) { String s = i.next(); System.out.println(s); } '
这段代码展示了一些在任意可迭代的集合数据类型中我们需要实现的东西:
1:集合数据类型必须实现一个iterator()方法并返回一个Iterator对象;
2:Iterator类必须包含两个方法:hasNext()(返回一个布尔值)和next()(返回集合中的一个泛型元素)。
对于可迭代的集合数据类型,Java已经为我们定义了所需的接口。要使一个类可迭代,第一步就是在它的声明中加入implements Iterable,对应的接口(即java.lang.Iterable)为:
’
public interface Iterable
{
Iterator iterator();
}
’
然后在类中添加一个方法iterator()返回一个迭代器Iterator。迭代器都是泛型的,因此我们可以使用参数类型Item来帮助用例遍历它们指定的任意类型的对象。对于一直使用的数组表示法,我们需要逆序迭代遍历这个数组,因此我们将迭代器命名为ReverseArrayIterator,并添加以下方法:
’
public Iterator iterator()
{
return new ReverseArrayIterator();
}
’
迭代器是什么?它是一个实现了hasNext()和next()方法的类的对象,由以下接口所定义(即java.util.Iterator)
‘public interface Iterator
{
boolean hasNext();
Item next();
void remove();
}
’
尽管接口指定了一个remove()方法,但在本书中remove()方法总为空,因为我们希望避免在迭代中穿插能够修改数据结构的操作。对于ReverseArrayIterator,这些方法都只需要一行代码,它们实现在栈类的一个嵌套类中:
’
private class ReverseArrayIterator implements Iterator
{
private int I = N;
public booelan hasNext() { return I > 0;}
public Item next() { return a[–i]; }
public void remove() { }
}
‘
栈的实现代码:
import java.util.Iterator; import java.util.NoSuchElementException; public class Stack<Item> { private Node first; private int N; private class Node{ Item item; Node next; } public boolean isEmpty(){ return first == null; } public int size() { return N; } public void push(Item item) { Node oldfirst = first; first = new Node(); first.item = item; first.next = oldfirst; N++; } public Item pop() { Item item = first.item; first = first.next; N--; return item; } public Item peek(){ if(isEmpty()) throw new NoSuchElementException("Stack underflow"); return first.item; } public Iterator<Item> iterator() { return new ListIterator(); } private class ListIterator implements Iterator<Item> { private Node current = first; public boolean hasNext() { return current != null; } public void remove(){} public Item next() { Item item = current.item; current = current.next; return item; } } }
相关文章推荐
- 动易2006序列号破解算法公布
- Ruby实现的矩阵连乘算法
- C#插入法排序算法实例分析
- 超大数据量存储常用数据库分表分库算法总结
- C#数据结构与算法揭秘二
- C#冒泡法排序算法实例分析
- 算法练习之从String.indexOf的模拟实现开始
- C#算法之关于大牛生小牛的问题
- C#实现的算24点游戏算法实例分析
- c语言实现的带通配符匹配算法
- 浅析STL中的常用算法
- 算法之排列算法与组合算法详解
- C++实现一维向量旋转算法
- Ruby实现的合并排序算法
- C#折半插入排序算法实现方法
- 基于C++实现的各种内部排序算法汇总
- C++线性时间的排序算法分析
- C++实现汉诺塔算法经典实例
- PHP实现克鲁斯卡尔算法实例解析
- C#获取关键字附近文字算法实例