您的位置:首页 > 理论基础 > 数据结构算法

数据结构学习笔记(四)之表、栈和队列

2018-02-10 21:21 295 查看
       本次讨论最简单的3中数据结构,接着上一个笔记的ADT的内容来说,对于集合ADT除了有关自身创建等的操作之外,还可以包括对数据的操作等,例如,查找,删除,增加等操作,数据结构不同,其对于不同的数据操作方式所体现的处理能力不同,具有不同的时间复杂度和空间复杂度。

      表的定义:

     表,顾名思义,直接的如我们的Excel表格,而在这里我们讨论的表与其有些不同,我们讨论它一行的情况,这样理解会对我们要讨论数据结构之中的表有一个较为直观的敢感受,在表格中的元素,如过它不再第一个位置,则前一个元素称为前区,后一个则称为后继,挺形象的,即使在中间的一个元素有前驱和后继,其包含的操作应该有printList和remove操作,以及insert,find,等。那我们怎么在计算机中实现呢?

     简单数组实现方式:

定义一个指定长度的数据,例如:

int [] arr = new int[10];
...
int[] newArr = new int [arr.length * 2];
for(int i=0;i<arr.length;i++){
newArr[i] = arr[i];
}


          对于上面的实现形式有以下优点:查询效率高,对于某些固定容量的,或者是容量不经常发生变化的,其主要作用主要用来读取查找的话,数组简单实现有一定的优势;起缺点也很明显,首先其容量的扩充问题,每次扩充需要新生成一个原来n倍的数组,之后还需要将原数组的元素转移到新的数组之中,这样非常耗时,对于插入的时间复杂度分析则需要注意其插入的位置,假如说在最末尾,那时间复杂度很小,如果在开头的话,则需要将所有的元素向后移动一个单位。

     简单链表实现方式:其为了避免插入和删除的线性开销将表使用不连续的地址进行储存,一般的数据链表有一个数据体和指针域组成,指针域指明了下一个元素的位置,而数据体则包含了所存放的数据,这种实现方式可以有效的进行插入和删除的工作,但是相对于数组存放,其查找效率要低一点。

而在Java中的Collections接口则定义了与数据操作相关的行为,接口同时扩展了Iterator接口,其定义了next,hasNext和remove方法,因此原始的Iterator接口仅可以用作遍历列表,在remove操作中,尽量使用iterator方法的remove方法,因为当使用iterator迭代器遍历得到待删除元素时,再进行删除要比原来直接删除算法要节省时间,不过要注意的一点是,在被iterator使用的列表,其结构发生改变是不合法的,也就是说,执行add,remove等方法是无效的,然而当我们使用迭代器自己的iterator的remove方法时,这时候则可以完成对应的操作。

    而List接口则相对应的有两个实现类,ArrayList类和LinkedList类,由于List接口继承了Collections接口,因此也需要实现Collections中定义的方法,ArrayList类的优势在于对于get和set方法为常数时间,其插入和删除的代价较大,除非是在这个列表的末尾。因此,LinkedList类提供了addFirst和removeFirst等操作首尾的方法,因为,联表中首尾的操作很耗费时间,其缺点也非常明显,其不容易索引,因此get方法则较为耗费时间。

      对于表的创建无论是ArrayList还是LinkedList,其创建表的时候所使用的时间都是常数时间,不过对于搜索来说,这两种线性结构都是低效率的,Coillections接口定义的contains和remove方法均为线性时间。

      ArrayList类模仿生成,不继承Collections类,但实现Iterable接口,将此类的类名定为MyArrayList类:

public class MyArrayList<AnyType> implements Iterable<AnyType>
{
/**
* Construct an empty ArrayList.
*/
public MyArrayList( )
{
doClear( );
}

/**
* Returns the number of items in this collection.
* @return the number of items in this collection.
*/
public int size( )
{
return theSize;
}

/**
* Returns true if this collection is empty.
* @return true if this collection is empty.
*/
public boolean isEmpty( )
{
return size( ) == 0;
}

/**
* Returns the item at position idx.
* @param idx the index to search in.
* @throws ArrayIndexOutOfBoundsException if index is out of range.
*/
public AnyType get( int idx )
{
if( idx < 0 || idx >= size( ) )
throw new ArrayIndexOutOfBoundsException( "Index " + idx + "; size " + size( ) );
return theItems[ idx ];
}

/**
* Changes the item at position idx.
* @param idx the index to change.
* @param newVal the new value.
* @return the old value.
* @throws ArrayIndexOutOfBoundsException if index is out of range.
*/
public AnyType set( int idx, AnyType newVal )
{
if( idx < 0 || idx >= size( ) )
throw new ArrayIndexOutOfBoundsException( "Index " + idx + "; size " + size( ) );
AnyType old = theItems[ idx ];
theItems[ idx ] = newVal;

return old;
}

@SuppressWarnings("unchecked")
public void ensureCapacity( int newCapacity )
{
if( newCapacity < theSize )
return;

AnyType [ ] old = theItems;
theItems = (AnyType []) new Object[ newCapacity ];
for( int i = 0; i < size( ); i++ )
theItems[ i ] = old[ i ];
}

/**
* Adds an item to this collection, at the end.
* @param x any object.
* @return true.
*/
public boolean add( AnyType x )
{
add( size( ), x );
return true;
}

/**
* Adds an item to this collection, at the specified index.
* @param x any object.
* @return true.
*/
public void add( int idx, AnyType x )
{
if( theItems.length == size( ) )
ensureCapacity( size( ) * 2 + 1 );

for( int i = theSize; i > idx; i-- )
theItems[ i ] = theItems[ i - 1 ];

theItems[ idx ] = x;
theSize++;
}

/**
* Removes an item from this collection.
* @param idx the index of the object.
* @return the item was removed from the collection.
*/
public AnyType remove( int idx )
{
AnyType removedItem = theItems[ idx ];

for( int i = idx; i < size( ) - 1; i++ )
theItems[ i ] = theItems[ i + 1 ];
theSize--;

return removedItem;
}

/**
* Change the size of this collection to zero.
*/
public void clear( )
{
doClear( );
}

private void doClear( )
{
theSize = 0;
ensureCapacity( DEFAULT_CAPACITY );
}

/**
* Obtains an Iterator object used to traverse the collection.
* @return an iterator positioned prior to the first element.
*/
public java.util.Iterator<AnyType> iterator( )
{
return new ArrayListIterator( );
}

/**
* Returns a String representation of this collection.
*/
public String toString( )
{
StringBuilder sb = new StringBuilder( "[ " );

for( AnyType x : this )
sb.append( x + " " );
sb.append( "]" );

return new String( sb );
}

/**
* This is the implementation of the ArrayListIterator.
* It maintains a notion of a current position and of
* course the implicit reference to the MyArrayList.
*/
private class ArrayList
4000
Iterator implements java.util.Iterator<AnyType>
{
private int current = 0;
private boolean okToRemove = false;

public boolean hasNext( )
{
return current < size( );
}

public AnyType next( )
{
if( !hasNext( ) )
throw new java.util.NoSuchElementException( );

okToRemove = true;
return theItems[ current++ ];
}

public void remove( )
{
if( !okToRemove )
throw new IllegalStateException( );

MyArrayList.this.remove( --current );
okToRemove = false;
}
}

private static final int DEFAULT_CAPACITY = 10;

private AnyType [ ] theItems;
private int theSize;
}
LinkedList类模仿生成,不继承Collections类,但实现Iterable接口,将此类的类名定为MyLinkedList类:
/**
* LinkedList class implements a doubly-linked list.
*/
public class MyLinkedList<AnyType> implements Iterable<AnyType>
{
/**
* Construct an empty LinkedList.
*/
public MyLinkedList( )
{
doClear( );
}

private void clear( )
{
doClear( );
}

/**
* Change the size of this collection to zero.
*/
public void doClear( )
{
beginMarker = new Node<>( null, null, null );
endMarker = new Node<>( null, beginMarker, null );
beginMarker.next = endMarker;

theSize = 0;
modCount++;
}

/**
* Returns the number of items in this collection.
* @return the number of items in this collection.
*/
public int size( )
{
return theSize;
}

public boolean isEmpty( )
{
return size( ) == 0;
}

/**
* Adds an item to this collection, at the end.
* @param x any object.
* @return true.
*/
public boolean add( AnyType x )
{
add( size( ), x );
return true;
}

/**
* Adds an item to this collection, at specified position.
* Items at or after that position are slid one position higher.
* @param x any object.
* @param idx position to add at.
* @throws IndexOutOfBoundsException if idx is not between 0 and size(), inclusive.
*/
public void add( int idx, AnyType x )
{
addBefore( getNode( idx, 0, size( ) ), x );
}

/**
* Adds an item to this collection, at specified position p.
* Items at or after that position are slid one position higher.
* @param p Node to add before.
* @param x any object.
* @throws IndexOutOfBoundsException if idx is not between 0 and size(), inclusive.
*/
private void addBefore( Node<AnyType> p, AnyType x )
{
Node<AnyType> newNode = new Node<>( x, p.prev, p );
newNode.prev.next = newNode;
p.prev = newNode;
theSize++;
modCount++;
}

/**
* Returns the item at position idx.
* @param idx the index to search in.
* @throws IndexOutOfBoundsException if index is out of range.
*/
public AnyType get( int idx )
{
return getNode( idx ).data;
}

/**
* Changes the item at position idx.
* @param idx the index to change.
* @param newVal the new value.
* @return the old value.
* @throws IndexOutOfBoundsException if index is out of range.
*/
public AnyType set( int idx, AnyType newVal )
{
Node<AnyType> p = getNode( idx );
AnyType oldVal = p.data;

p.data = newVal;
return oldVal;
}

/**
* Gets the Node at position idx, which must range from 0 to size( ) - 1.
* @param idx index to search at.
* @return internal node corresponding to idx.
* @throws IndexOutOfBoundsException if idx is not between 0 and size( ) - 1, inclusive.
*/
private Node<AnyType> getNode( int idx )
{
return getNode( idx, 0, size( ) - 1 );
}

/**
* Gets the Node at position idx, which must range from lower to upper.
* @param idx index to search at.
* @param lower lowest valid index.
* @param upper highest valid index.
* @return internal node corresponding to idx.
* @throws IndexOutOfBoundsException if idx is not between lower and upper, inclusive.
*/
private Node<AnyType> getNode( int idx, int lower, int upper )
{
Node<AnyType> p;

if( idx < lower || idx > upper )
throw new IndexOutOfBoundsException( "getNode index: " + idx + "; size: " + size( ) );

if( idx < size( ) / 2 )
{
p = beginMarker.next;
for( int i = 0; i < idx; i++ )
p = p.next;
}
else
{
p = endMarker;
for( int i = size( ); i > idx; i-- )
p = p.prev;
}

return p;
}

/**
* Removes an item from this collection.
* @param idx the index of the object.
* @return the item was removed from the collection.
*/
public AnyType remove( int idx )
{
return remove( getNode( idx ) );
}

/**
* Removes the object contained in Node p.
* @param p the Node containing the object.
* @return the item was removed from the collection.
*/
private AnyType remove( Node<AnyType> p )
{
p.next.prev = p.prev;
p.prev.next = p.next;
theSize--;
modCount++;

return p.data;
}

/**
* Returns a String representation of this collection.
*/
public String toString( )
{
StringBuilder sb = new StringBuilder( "[ " );

for( AnyType x : this )
sb.append( x + " " );
sb.append( "]" );

return new String( sb );
}

/**
* Obtains an Iterator object used to traverse the collection.
* @return an iterator positioned prior to the first element.
*/
public java.util.Iterator<AnyType> iterator( )
{
return new LinkedListIterator( );
}

/**
* This is the implementation of the LinkedListIterator.
* It maintains a notion of a current position and of
* course the implicit reference to the MyLinkedList.
*/
private class LinkedListIterator implements java.util.Iterator<AnyType>
{
private Node<AnyType> current = beginMarker.next;
private int expectedModCount = modCount;
private boolean okToRemove = false;

public boolean hasNext( )
{
return current != endMarker;
}

public AnyType next( )
{
if( modCount != expectedModCount )
throw new java.util.ConcurrentModificationException( );
if( !hasNext( ) )
throw new java.util.NoSuchElementException( );

AnyType nextItem = current.data;
current = current.next;
okToRemove = true;
return nextItem;
}

public void remove( )
{
if( modCount != expectedModCount )
throw new java.util.ConcurrentModificationException( );
if( !okToRemove )
throw new IllegalStateException( );

MyLinkedList.this.remove( current.prev );
expectedModCount++;
okToRemove = false;
}
}

/**
* This is the doubly-linked list node.
*/
private static class Node<AnyType>
{
public Node( AnyType d, Node<AnyType> p, Node<AnyType> n )
{
data = d; prev = p; next = n;
}

public AnyType data;
public Node<AnyType>   prev;
public Node<AnyType>   next;
}

private int theSize;
private int modCount = 0;
private Node<AnyType> beginMarker;
private Node<AnyType> endMarker;
}
详细的参考案例请见此链接。

栈ADT 的实现可以使用ArrayList和LinkedList任何一种实现,栈的作用主要是一种先进后出的数据操作方式的列表实现。因此列表可以实现栈的操作,具体的应用有以下几个放面:

1.符号的平衡,最直接的说法就是语句中的括号的匹配问题,可以通过一个简单的算法来实现,而不必去实现一个专门的大型程序。

2.后缀表达式,或者称为逆波兰表达式,结合一个例子演示一下:6523+8*3+*,当遇到一个数字时,就将数字压入栈中,如果遇到两个符号,就将两个数字弹出来,结合这个符号计算,得到的结果再次压入栈中:

第一次:栈中的元素有6,5,2,3

当遇到+号时,栈中的元素有6,5,5,接着,8也被压入到栈中。当遇到*号时,弹出8和5,得到5*8=40;将40压入栈中,接着又见到一个‘+’号,因此,40和5被弹出,并且5+40=45,再将45压入栈中,再将3压入栈中,碰到了+号,则得到45+3=48;最后遇到一个*号,从栈中弹出48和6,将得到结果48*6=288.话费的时间为线性,如果一个算式的后缀表达式给出了,就不必知道任何优先规则,这是一个明显的优势。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构 数据 算法