1、表
这里指的表是形如A0、A1......An的一般的表。将大小为0的特殊表称为空表。除空表外的任何表,我们说Ai后继Ai-1并称Ai-1前驱Ai。
表的简单数组实现
设定数组的初始长度为10:int [] arr = new int[10];
扩展数组:
int [] new Arr = new int(arr.length*2);
许多情况下,数组是表的合适实现,特别是在数组插入后很少修改,查询比较多的情况下。如果要处理删除、插入操作比较多的情况那么需要另外的结构的表:链表。
链表
链表由一系列节点构成,这些节点与数组中的元素不同,不必再内存中相连。每个节点均有后面一个节点的链接。
循环链表:将单链表的首尾相连即成为循环链表。
单链表、双链表比较:
1、单链表增加删除节点简单,缺点是只能从头到尾遍历,只能找到后继,无法找到前驱,也就是只能前进。
2、双链表能够找到前驱和后继,可进可退。
java语言实现数组和链表的操作:arraylist和linkedlist
arraylist实现:
/**
* 集合arraylist的实现
*/
public class MyArrayList<E> implements Iterable<E> {
private static final int DEFAULT_CAPACITY = 10;
private int theSize;
private E [] theItems;
public MyArrayList(){
doClear();
new ArrayList<E>();
}
/**
* java源码clear的实现
*
* protected void removeRange(int fromIndex, int toIndex) {
*ListIterator<E> it = listIterator(fromIndex);
*for (int i=0, n=toIndex-fromIndex; i<n; i++) {
*it.next();
*it.remove();
*}
*}
*/
private void doClear() {
theSize = 0;
//这里的清除数组中元素有错误,ensureCapacity只是将旧的数组的元素赋值给新的数组
ensureCapacity(DEFAULT_CAPACITY);
}
public boolean isEmpty(){
return theSize==0;
}
public void trimToSize(){
ensureCapacity(size());
}
public E get(int idx){
if(idx<0 || idx>=size()){
throw new ArrayIndexOutOfBoundsException();
}
return theItems[idx];
}
public E set(int idx, E newVal){
if(idx<0||idx>=size()){
throw new ArrayIndexOutOfBoundsException();
}
E old = theItems[idx];
theItems[idx] = newVal;
return old;
}
public void ensureCapacity(int capacity) {
if(capacity<theSize){
return;
}
E [] old = theItems;
theItems = (E[])new Object[capacity];
for(int i=0; i<size();i++){
theItems[i] = old[i];
}
}
public int size(){
return theSize;
}
public void clear(){
doClear();
}
public boolean add(E val){
add(size(), val);
return true;
}
private void add(int idx, E val){
//数组中元素满的话扩充数组
if(theItems.length==size()){
ensureCapacity(size()*2+1);
}
for (int i = theSize; i >idx ; i--) {
theItems[i] = theItems[i-1];
}
theItems[idx] = val;
theSize++;
}
public E remove(int idx){
if(idx<0||idx>=size()){
throw new ArrayIndexOutOfBoundsException();
}
E removeItems = theItems[idx];
for(int i=idx;i<size();i++){
theItems[i] = theItems[i+1];
}
theSize--;
return removeItems;
}
@Override
public Iterator<E> iterator() {
return new ArrayListIterator();
}
private class ArrayListIterator implements Iterator<E> {
private int current = 0;
@Override
public boolean hasNext(){
return current<size();
}
@Override
public E next() {
if(!hasNext()){
throw new NoSuchElementException();
}
return theItems[current++];
}
@Override
public void remove(){
MyArrayList.this.remove(--current);
}
}
}
linkedList的实现使用双向链表结构:
/**
* 链表的插入、添加、删除实现
*/
public class MyLinkedList<E> implements Iterable<E> {
private int theSize;
private int modCount = 0;
private Node<E> beginMarker;
private Node<E> endMarker;
public int size(){
return theSize;
}
public boolean isEmpty(){
return theSize==0;
}
public boolean add(E ele){
add(size(), ele);
return true;
}
public E get(int idx){
return getNode(idx).data;
}
public E set(int idx, E newVal){
//这里应该加上下标是否越界的判断
Node<E> p = getNode(idx);
E oldValue = p.data;
p.data = newVal;
return oldValue;
}
public E remove(int idx){
return remove(getNode(idx));
}
public E remove(Node<E> p ){
p.nex.pre = p.pre;
p.pre.nex = p.nex;
theSize--;
modCount--;
return p.data;
}
private void add(int idx, E ele) {
addBefore(getNode(idx,0,size()),ele);
}
private void addBefore(Node<E> node, E ele) {
Node<E> newNode = new Node<E>(ele,node.pre,node);
newNode.pre.nex = newNode;
node.pre = newNode;
theSize++;
modCount++;
}
public Node<E> getNode(int idx){
return getNode(idx,0,size()-1);
}
private Node<E> getNode(int idx, int lower, int upper) {
Node<E> p = null;
if(idx<lower || idx>upper){
throw new IndexOutOfBoundsException();
}
//根据下标的位置判断是从链表的前半部分找还是从后半部分找
if(idx<size()/2){
p = beginMarker.nex;
for(int i=0;i<idx;i++){
p = p.nex;
}
}else{
for (int i = size(); i <idx ; i--) {
p = p.pre;
}
}
return p;
}
@Override
public Iterator<E> iterator() {
return new LinkedListIterator();
}
private static class Node<E>{
E data;
Node<E> pre;
Node<E> nex;
public Node(E ele, Node<E> pev, Node<E> next){
this.data = ele;
this.pre = pev;
this.nex = next;
}
}
public MyLinkedList(){
doClear();
}
public void clear(){
doClear();
}
private void doClear(){
beginMarker = new Node<E>(null,null,null);
endMarker = new Node<E>(null, beginMarker, null);
theSize = 0;
modCount++;
}
private class LinkedListIterator implements Iterator<E> {
private Node<E> current = beginMarker.nex;
private int expectedModCount = modCount;
private boolean okToRemove = false;
@Override
public boolean hasNext() {
return current!=endMarker;
}
@Override
public E next() {
if(modCount!=expectedModCount){
throw new ConcurrentModificationException();
}
if(!hasNext()){
throw new NoSuchElementException();
}
E nextItem = current.data;
current = current.nex;
okToRemove = true;
return nextItem;
}
@Override
public void remove() {
if(modCount!=expectedModCount){
throw new ConcurrentModificationException();
}
if(!okToRemove){
throw new IllegalStateException();
}
MyLinkedList.this.remove(current.pre);
expectedModCount++;
okToRemove = false;
}
}
}
2、栈
栈是限制插入和删除只能在一个位置上进行的表,该位置是表的末端,叫做栈的顶(top)。对栈的基本操作有push(进栈)和pop(出栈)。
栈的实现一般有两种方法:链式结构、数组。栈的实现是上面的数组和链表实现的简化。
3、队列
队列也是表,使用队列时插入在一端,删除在另一端,也就是先进先出。
队列的基本操作是enqueue(入队)和dequeue(出队),也就是在表的末端插入一个元素和在取出表的开头的元素。
队列的链表实现
下面的实现是使用双链表实现
/**
* 队列的实现
* @param <E>
*/
public class MyQueue<E> {
private int theSize = 0;
private Node<E> node;
private Node<E> beginMarker = null;
private Node<E> endMarker = null;
public int size(){
return theSize;
}
//队列插入数据
public boolean enQueue(E ele){
if(size()==0){
beginMarker.data = ele;
beginMarker.next = endMarker;
endMarker.pre = beginMarker;
}
Node<E> newNode = new Node<E>(ele,endMarker,null);
endMarker.pre.next = newNode;
newNode.pre = endMarker.pre;
newNode.next = endMarker;
endMarker.pre = newNode;
theSize++;
return true;
}
/**
* 从队列中取出数据
* @return
*/
public E deQueue(){
Node<E> node = beginMarker.next;
beginMarker.next = node.next;
node.next.pre = beginMarker;
return node.data;
}
private static class Node<E> {
private E data;
private Node<E> next;
private Node<E> pre;
private Node(E ele, Node<E> pre){
new Node(ele, pre, null);
}
private Node(E ele, Node<E> pre, Node<E> next){
this.data =ele;
this.next =next;
this.pre = pre;
}
}
}