| Uutiset | Koodikirjasto | Wiki | Keskustelut | FAQ | Info |
Treesortcoderodde 04.08.12 19:13 Helppo sortausalgoritmi, joka osoittautuu tehokkaaksi satunnaisesti generoidulla datalla ja keskisuurilla listoilla.
package com.mureakuha.util; import java.util.ArrayList; import java.util.Arrays; import java.util.Iterator; import java.util.Random; import java.util.TreeMap; public class Main { /** * This class represents an unbalanced binary search tree. Provides only * minimum functionality needed in <code>Treesort</code>. * * @param <T> the element type. */ static class Tree<T extends Comparable<? super T>> implements Iterable<T>{ static class Node<T extends Comparable<? super T>> { T value; Node<T> left; Node<T> right; Node<T> parent; Node( T value ){ this.value = value; } } private Node<T> root; private int size; /** * Inserts a value into this <code>Tree</code>. * * @param value the value to insert. */ void insert( T value ){ Node<T> newNode = new Node<T>( value ); if( root == null ) { size = 1; root = newNode; return; } Node<T> current = root; int cmp; for(;;) { if( (cmp = value.compareTo( current.value )) < 0 ) { if( current.left != null ) current = current.left; else break; } else { if( current.right != null ) current = current.right; else break; } } if( cmp < 0 ) current.left = newNode; else current.right = newNode; newNode.parent = current; size++; } /** * Returns the successor node of <code>node</code>. * * @param node the node whose successor to search. * * @return the successor node of <code>node</code> or <code>null</code> * if <code>node</code> is the rightmost node, i.e., has no successor. */ Node<T> successor( Node<T> node ){ if( node.right == null ) { while( node.parent != null && node.parent.right == node ) node = node.parent; if( node.parent == null ) return null; else return node.parent; } node = node.right; while( node.left != null ) node = node.left; return node; } /** * Gets a tree iterator for this <code>Tree</code>. * * @return a tree iterator. */ public Iterator<T> iterator(){ return new TreeIterator(); } /** * This class traverses a <code>Tree</code> in-order. */ public class TreeIterator implements Iterator<T>{ private int retrieved; private Node<T> current; public TreeIterator(){ current = root; // Go point to the least value node. if( current != null ) while( current.left != null ) current = current.left; } public boolean hasNext(){ return retrieved < size; } public T next(){ if( retrieved == 0 ) { retrieved = 1; return current.value; } Node<T> node = successor( current ); current = node; retrieved++; return current.value; } public void remove(){ throw new UnsupportedOperationException(); } } } /** * Generates an array holding elements of <code>array</code>, but in * ascending order. This method utilizes a binary search tree * (not balanced), which is sufficient on random data, but may degrade to * O(n * n)-behavior if <code>array</code> has rather high "presortedness" * (e.g. is already in ascending or descending order). On random data, and * if element count is at most 3.75e5, provides performance comparable to * Mergesort or even better. * * @param <T> the element type; should be <code>Comparable</code>. * @param array the array whose values to put in order. * * @return the sorted result array. */ public static <T extends Comparable<? super T>> T[] Treesort( T[] array ){ Tree<T> tree = new Tree<T>(); T[] result = array.clone(); int i = 0; // Load the elements into the tree. for( T element : array ) tree.insert( element ); // Iterate the elements in ascending order and store them in the result // array. for( T element : tree ) result[i++] = element; return result; } /** * Generates a sorted array using the values in <code>array</code> (which * it does not modify). The approach is the same as in * <code>Treesort</code>, but the underlying tree structure is balanced, * which guarantees O(n log n)-behavior in any case. * * @param <T> the element type, should be <code>Comparable</code>. * @param array the array whose values to sort. * * @return the sorted result array. */ public static <T extends Comparable<? super T>> T[] RBTreesort( T[] array ){ // TreeMap is implemented as a red-black -tree. TreeMap<T, ArrayList<T>> map = new TreeMap<T, ArrayList<T>>(); T[] result = array.clone(); int i = 0; // Store the values to sort in the tree. for( T element : array ) if( map.containsKey( element ) ) map.get( element ).add( element ); else { ArrayList<T> list = new ArrayList<T>(); list.add( element ); map.put( element, list ); } // Iterate the tree in value increasing order and store sequentially the // values in the result array. for( T key : map.keySet() ) for( T element : map.get( key ) ) result[i++] = element; return result; } public static void main( String... args ){ final int N = 100000; Integer[] array1 = getRandomArray( N, 533 ); Integer[] array2 = array1.clone(); Integer[] array3 = array1.clone(); System.out.println( "Sorting random data of " + N + " elements:\n" ); long ta = System.currentTimeMillis(); Integer[] result = Treesort( array1 ); long tb = System.currentTimeMillis(); System.out.println( "Treesort(): " + (tb - ta) + " ms." ); System.out.println( "Is sorted: " + isSorted( result ) + "\n" ); ta = System.currentTimeMillis(); Integer[] result2 = RBTreesort( array2 ); tb = System.currentTimeMillis(); System.out.println( "RBTreesort(): " + (tb - ta) + " ms." ); System.out.println( "Is sorted: " + isSorted( result2 ) + "\n" ); ta = System.currentTimeMillis(); Arrays.sort( array3 ); tb = System.currentTimeMillis(); System.out.println( "Arrays.sort(): " + (tb - ta) + " ms." ); System.out.println( "Is sorted: " + isSorted( array3 ) + "\n" ); System.out.println( "Treesort() sorts stably: " + areEqual( array3, result ) ); System.out.println( "RBTreesort() sorts stably: " + areEqual( array3, result2 ) ); } /** * Allocates and returns a random integer array. * * @param size the size of the result array. * @param seed the seed for the PRNG. * * @return a random integer array. */ public static Integer[] getRandomArray( int size, long seed ){ Random r = new Random( seed ); Integer[] array = new Integer[size]; for( int i = 0; i < size; i++ ) array[i] = r.nextInt( size ); return array; } /** * Checks whether an array is in ascending order. * * @param array the array against which the test is run. * * @return <code>true</code> if the argument array is in ascending order; * <code>false</code> otherwise. */ public static boolean isSorted( Integer[] array ){ for( int i = 0; i < array.length - 1; i++ ) if( array[i].compareTo( array[i + 1] ) > 0 ) return false; return true; } /** * Checks whether the argument arrays contain the same references in the * same order. * * @param array1 the first array to check. * @param array2 the second array. * * @return <code>true</code> if <code>array1</code> and <code>array2</code> * both have the same length and for each index <code>i</code> * <code>array1[i] == array2[i]</code>; <code>false</code> otherwise. */ public static boolean areEqual( Integer[] array1, Integer[] array2 ){ if( array1.length != array2.length ) return false; for( int i = 0; i < array1.length; i++ ) if( array1[i] != array2[i] ) return false; return true; } } editoitu: 19:16 4.8.12 coderodde 19:16 4.8.12 Jos käytössäsi on JDK 7 (Arrays.sort:na Tim sort), Treesort alkaa olla hitaampi yli 375000:n alkion listoilla (vaikkakin randomeilla), ja JDK 6:ssa tällaisena kynnyksenä on noin puoli miljoona alkiota. coderodde 17:13 6.8.12 Introduction to Algorithms, 3rd ed. -opuksessa sivulla 300 on seuraava lause: The expected height of a randomly built [unbalanced] binary search tree on n distinct keys is O(lg n). Tarkoittaa, että Treesort omaa odotetusti O(n lg n) -käyttäytymisen satunnaisella datalla. |
![]() Haku
|