/**
* Copyright (c) 2003-2009, Xith3D Project Group all rights reserved.
*
* Portions based on the Java3D interface, Copyright by Sun Microsystems.
* Many thanks to the developers of Java3D and Sun Microsystems for their
* innovation and design.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* Neither the name of the 'Xith3D Project Group' nor the names of its
* contributors may be used to endorse or promote products derived from this
* software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) A
* RISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE
*/
package org.xith3d.utility.general;
import java.util.ArrayList;
/**
* :Id: SparseVector.java,v 1.5 2003/02/24 00:13:51 wurp Exp $
*
* :Log: SparseVector.java,v $
* Revision 1.5 2003/02/24 00:13:51 wurp
* Formatted all java code for cvs (strictSunConvention.xml)
*
* Revision 1.4 2001/06/20 04:05:42 wurp
* added log4j.
*
* Revision 1.3 2001/01/28 07:52:20 wurp
* Removed <dollar> from Id and Log in log comments.
* Added several new commands to AdminApp
* Unfortunately, several other changes that I have lost track of. Try diffing this
* version with the previous one.
*
* Revision 1.2 2000/12/16 22:07:33 wurp
* Added Id and Log to almost all of the files that didn't have it. It's
* possible that the script screwed something up. I did a commit and an update
* right before I ran the script, so if a file is screwed up you should be able
* to fix it by just going to the version before this one.
*
* @author David Yazel
*/
public class SparseVector< T >
{
/**
* Class for holding information on a single node, including links to the
* next and prior node.
*/
private class LinkedNode
{
public LinkedNode next;
public LinkedNode prev;
public T obj;
public int i;
public LinkedNode( int i, T obj )
{
this.i = i;
this.obj = obj;
next = null;
prev = null;
}
}
private LinkedNode first = null;
private LinkedNode last = null;
public SparseVector()
{
}
/**
* Used to find the predecessor of a particular index.
*
* @return null if there is no predecessor, the predecessor otherwise
*/
private LinkedNode findPred( int i )
{
LinkedNode p1;
LinkedNode p2;
p1 = null;
p2 = first;
while ( p2 != null )
{
if ( p2.i >= i )
{
return p1;
}
p1 = p2;
p2 = p2.next;
}
return p1;
}
/**
* Inserts the element at the location specified. If the element already exists then
* the object will be replaced
*/
public void insertAt( int i, T obj )
{
LinkedNode node = new LinkedNode( i, obj );
if ( first == null )
{
node.prev = null;
node.next = null;
node.obj = obj;
first = node;
last = node;
}
else
{
LinkedNode pred = findPred( i );
// if there is no predecessor then link the node into front of
// the list
if ( pred == null )
{
node.next = first;
node.prev = null;
first.prev = node;
first = node;
/*
} else if (pred.next.i == i) {
pred.next.obj = obj;
*/
}
else
{
node.prev = pred;
node.next = pred.next;
pred.next = node;
if ( node.next != null )
{
node.next.prev = node;
}
}
}
}
/**
* @return the linked node at the position specified or null if
* the node is not there.
*/
private LinkedNode nodeAt( int i )
{
if ( first == null )
{
return ( null );
}
LinkedNode pred = findPred( i );
if ( pred == null )
{
if ( first.i == i )
{
return ( first );
}
return null;
}
if ( pred.next == null )
{
return ( null );
}
if ( pred.next.i == i )
{
return ( pred.next );
}
return ( null );
}
/**
* @return the element at the location specified or null if the
* the object does not exist
*/
public T elementAt( int i )
{
LinkedNode node = nodeAt( i );
if ( node == null )
return ( null );
return ( node.obj );
}
/**
* Removes the specified element from the list.
*/
public void removeAt( int i )
{
LinkedNode node = nodeAt( i );
if ( node != null )
{
if ( last == node )
{
last = node.prev;
}
if ( first == node )
{
first = node.next;
}
if ( node.prev != null )
{
node.prev.next = node.next;
}
if ( node.next != null )
{
node.next.prev = node.prev;
}
}
}
/**
* Sorts all the elements into two categories, those that fall within certain
* certain bounds, and those that fall without those same bounds.
*/
public void sortElements( ArrayList< T > within, ArrayList< T > without, int start, int stop )
{
LinkedNode p = first;
while ( p != null )
{
if ( ( p.i < start ) || ( p.i > stop ) )
{
without.add( p.obj );
}
else
{
within.add( p.obj );
}
p = p.next;
}
}
/*
// test the code
public static void main( String[] args )
{
final int NUM = 15000;
Random r = new Random( 164372 );
HashSet< Integer > map = new HashSet< Integer >( NUM );
SparseVector< Integer > v;
// build the test cases
System.out.println( "Building test cases" );
int n = 0;
while ( n < NUM )
{
int i = r.nextInt( 8000000 );
if ( !map.contains( i ) )
{
map.add( i );
n++;
}
}
System.out.println( "Inserting test cases into SparseVector" );
v = new SparseVector< Integer >();
for ( Integer i: map )
{
v.insertAt( i.intValue(), i );
}
System.out.println( "Getting all the test cases from SparseVector in order" );
Object[] objs = map.toArray();
for ( int i = 0; i < NUM; i++ )
{
Integer obj = (Integer)objs[ i ];
Integer found = (Integer)v.elementAt( obj.intValue() );
if ( found == null )
{
System.out.println( "Error finding test case in sparse vector" );
System.exit( 0 );
}
if ( found.intValue() != obj.intValue() )
{
System.out.println( "Error matching retrieved value" );
System.exit( 0 );
}
}
System.out.println( "Removing 25 percent of items..." );
for ( int i = (int)( NUM * 0.75f ); i < NUM; i++ )
{
Integer obj = (Integer)objs[ i ];
v.removeAt( obj.intValue() );
n--;
}
System.out.println( "Checking test cases again" );
for ( int i = 0; i < n; i++ )
{
Integer obj = (Integer)objs[ i ];
Integer found = (Integer)v.elementAt( obj.intValue() );
if ( found == null )
{
System.out.println( "Error finding test case in sparse vector" );
System.exit( 0 );
}
if ( found.intValue() != obj.intValue() )
{
System.out.println( "Error matching retrieved value" );
System.exit( 0 );
}
}
System.out.println( "Test complete" );
}
*/
}