java集合源码解读---Queu和Stack的数组和链式实现
2015-11-04 19:22
483 查看
栈和队列
所谓的栈,是一个含有至少两个基本操作的抽象数据类型:插入新的元素;删除最近时间插入的元素。遵循FILO(First in,last out,先进后出)的原则。所谓的队列,也是一个含有至少两个基本操作的抽象数据类型:插入新的元素;删除最久时间插入的元素。遵循FIFO(First in,first out,先进先出)的原则。
关于栈和队列的具体实现,我们即可以借助于数组,也可以采用链表来实现。
1) 栈的数组实现方式
java代码
public class MyStack <E>{ public int count; public Object[] items; public MyStack() { items = new Object[20]; count = 0; } public MyStack(int len) { items = new Object[len]; count = 0; } //判断栈是否为空 boolean isEmpty(){return count==0;} //重整数组的大小 private void resize(int size) { Object[] newItems = new Object[size]; for(int i =0;i<count;i++) newItems[i] = items[i]; items = newItems; } //进栈 public void push(E e) { //如果栈满,则重整数组大小。 if(count == items.length) resize(2*items.length); items[count++] = e;//数组的起始索引是0,入栈后,数组的大小应增加1 } //出栈 public E pop() { if(count==0) return null; //如果栈为空 E item = (E)items[count-1]; items[count-1] = null; count--; //重整数组大小,节省存储空间。 if(count>0&&count<=items.length/4) resize(items.length/2); return item; } //返回栈中的最后一个元素 public E peek() { if(count==0) return null; E item = (E)items[count-1]; return item; } }
2)栈的链式实现方式
java代码
public class MyStack<E> { Node head;//表示栈顶 private class Node<E> { E item; Node next; } public boolean isEmpty() { return head==null; } public void push(E e) { Node<E> node = new Node(); node.item = e; node.next = head; //栈的物理连接顺序是从上到下 head = node; } public E pop() { if(head==null) return null; E e = (E)head.item;//栈顶元素先出 head=head.next; return e; } public E peek() { if(head == null) return null; else return (E)head.item; } }
3)队列的数组实现方式
java代码
//用数组实现循环队列 public class ArrayQueue <E> { private int front; private int rear; private int capacity; private int count; private int capacityIncrement; private Object[] itemArray; public ArrayQueue(){ front = 0; rear = 0; count = 0; capacity = 10; capacityIncrement = 5;//新增队列的长度。 itemArray = new Object[capacity]; } boolean isEmpty() {return count==0;} //1.入队 public void insert(E e) { //1.如果队列已满,就先扩充队列,后插队。 if(count==capacity) { capacity+=capacityIncrement; Object[] newArray = new Object[capacity]; /** * 将原队列中的元素原样拷贝到新队列中。如果不是原样拷贝,则会破坏队列的FIFO特性。 */ //如果队列中的元素位于itemArray[font.....rear-1]中 if(front<rear){ for(int i = front;i<rear;i++){ newArray[i] = itemArray[i]; } } else{ //因队列已满,此时front==rear,应该将队列分成两个区间:[0:rear-1] 和[front:count-1],分别拷贝到新数组的两端。 //在原队列的中间插入一段新的存储空间。 //否则,如果在原队列的后面插入新的空间,那么再次进行入队操作时,原来的元素就会被覆盖掉。 for(int i =0;i<rear;i++){newArray[i] = itemArray[i];} for(int i = front;i<count;i++) {newArray[i+capacityIncrement] = itemArray[i];} front+=capacityIncrement;//然后,将front改为指向其新位置. } itemArray = newArray; } //2.如果队列未满,直接插队。 itemArray[rear]=e; rear=(rear+1)%capacity; count++; } //2.出队 public E remove() { if(count==0) return null; else{ E item = (E)itemArray[front]; itemArray[front] = null; front = (front+1)%capacity; count--; return item; } } } //另外一种数组实现循环队列的简单实现 import java.util.NoSuchElementException; public class SimpleArrayQueue { protected Object [] data; protected int size, head, tail; public SimpleArrayQueue(){ final int INITIAL_LENGTH=10; data=new Object[INITIAL_LENGTH]; size=0; head=0; tail=-1; } //获取队列的大小和判断队列是否为空 public int theSize(){ return size;} public boolean isEmpty(){ return size==0;} //获取队头元素 public Object front(){ if(size==0) throw new NoSuchElementException(); return data[head]; } //入队操作 public void enqueue(Object element){ if(size==data.length){ //在java中允许将一个数组变量拷贝给另外一个数组变量。这时,两个变量将引用同一个数组。 Object [] oldData=data;//保存原数组data data=new Object[data.length*2]; //double the length of data //将数组分成两个区间进行拷贝:区间1:[head:OldData.length-1]和区间2:[0:tail] //当head==0时,原数组只有区间1这一段需要被拷贝,当head>0时,原数组有区间1和区间2这两段需要被拷贝。 //copy oldData[head:OldData.length-1] to data[0:OldData.length-1-head] System.arraycopy(oldData, head,data,0,oldData.length-head); /* * 如果希望将一个数组的所有值拷贝到一个新的数组中去,就要使用Arrays类中的copyOf()方法: * int[] copiedLckyNumbers = Arrays.copyOf(luckyNumbers,2*luckyNumbers.length); * 第二个参数是新数组的长度,这个方法通常用来增加数组的大小。 * 如果数组的元素是数值型,那么多余的元素将被赋值为0;如果是boolean,多余的元素将会被赋值为false; * 相反,如果长度小于原始数组的长度,则只会拷贝最前面的数据元素。 */ if(head>0)//拷贝区间2 //copy oldData[0:tail] to data [oldData.length-head:oldlenght-1] //System.arraycopy(oldData, 0, data, head+1, tail+1); //错误写法 System.arraycopy(oldData, 0, data,oldData.length-head, tail+1);//正确写法 head=0; tail=oldData.length-1; } tail=(tail+1)%data.length; data[tail]=element; size++; } //出队操作 public Object dequeue(){ /* 注意 : * if(size--==0){throw new NoSuchElementException();}//先执行if(size==0),后执行size--; * 放置的顺序。 * 不能写成if(--size==0){ throw new NoSuchElementException(); } * 因为当队列中就剩下一个元素时,--size;会使size为0,此时抛出异常,并没有对该异常进行处理。 * 程序中断,后面的语句无法执行。 */ Object element=data[head]; head=(head+1)%data.length;//当队列满的时候size==data.length,即data.length就是当前size的值。 //如果size变小后,head就会跳过下一个元素,而不是顺移下一个,导致下一个元素被”遗忘“了。 if(size--==0){ throw new NoSuchElementException(); } //先执行if(size==0),后执行size--; return element; //程序最后一句一定要是return语句。 } }
4)队列的链式实现方式
java代码
public class ListQueue <E>{ private int count; private Node<E> front,rear; private class Node<E> { E item; Node link; } // //提供java类的空参数的构造函数。 // ListQueue() // { // count =0; // front = null; // rear = null; // Node<E> node = new Node<E>(); // } public boolean isEmpty(){ return count==0;} //入队 public void insert(E e) { Node<E> newNode = new Node<E>();//初始化为空节点。 newNode.item = e; //如果队为空 if(rear==null) front = rear = newNode; else{ rear.link = newNode;//新节点连接到队尾处 rear = newNode;//新节点变成队尾 } count++; } //出队 public E remove() { //如果队为空 if(count==0) return null; else{ E item = front.item; front = front.link; if(front==null) { rear = null; }//队列为空。 count--; return item; } } //克隆队列 public ListQueue<E> clone() { ListQueue<E>Q = new ListQueue<E>(); for(Node<E>t=front;t!=null;t=t.link)//for循环的这种写法。等价于while循环。 Q.insert(t.item); return Q; } }
相关文章推荐
- POJ1679-The Unique MST
- iOS监听UITextView、UITextField键盘删除键
- iOS--错误集锦--UI控件不显示原因之一
- 3D-Touch Home Screen Quick Actions 使用
- 移动UI/UX设计师和PM使用的原型工具
- iOS求生之路(三)(UIAlertView的用法)
- iphone 与 iPad在开发中的区别以及iPad中的UIPopoverController的使用
- iOS9 UIPopoverViewController
- Archive 创建报错问题
- iOS_通过UIBezierPath实现简单的画板功能
- iOS-UI控件精讲之UILabel
- UISegmentedControll,UISlider,UISwitch,UIStepper
- 写给程序员和UI--Android的切图标准
- ios开发系列-UITableController-动态页面
- JPA 学习篇(四)Query接口下的 API 测试
- UILabel 和UIButton的简单实用
- uiCoder界面代码生成工具 part1 概述+图片制作
- The JSP specification requires that an attribute name is preceded by whitespace异常
- IQueryable接口与IEnumberable 区别
- Android设计模式——Builder模式