E81086713E446D36F62B2AA2A3502B5EB155

Java杂家

杂七杂八。。。一家之言

BlogJava 首页 新随笔 联系 聚合 管理
  141 Posts :: 1 Stories :: 174 Comments :: 0 Trackbacks

#

外部排序实现使用堆来生成若干个顺串,然后使用多路归并算法来生成最终排序好的内容。

本来打算使用败者树,结果发现败者树当参与的竞赛者相对较多的情况下,没有全部完成就被空节点充满了。
这个按照它的严格算法,其实也是可以知道不能保证总是能排完的。天快亮了,才彻底放弃使用败者树。改成实现赢者树,结果发现赢者树能保证不出错,实现竟也顺手。

最后整了个测试文件500M的随机内容,2~3分钟排序完成了(应该还可以优化),感觉还行。

代码较多,最要考虑到以后可能要重用。

package algorithms.extsort;

import java.io.IOException;

import algorithms.MinHeap;

/**
 * 
@author yovn
 *
 
*/
public class ExternalSorter {
    
        
    
    
public void sort(int heapSize,RecordStore source,RunAcceptor mediator ,ResultAcceptor ra)throws IOException
    {
        MinHeap
<Record> heap=new MinHeap<Record>(Record.class,heapSize);
        
for(int i=0;i<heapSize;i++)
        {
            Record r
=source.readNextRecord();
            
if(r.isNull())break;
            heap.insert(r);
        }
        
        Record readR
=source.readNextRecord();
        
while(!readR.isNull()||!heap.isEmpty())
        {
        
            Record curR
=null;
            
//begin output one run
            mediator.startNewRun();
            
while(!heap.isEmpty())
            {
                curR
=heap.removeMin();
            
                mediator.acceptRecord(curR);
                
                
if (!readR.isNull()) {
                    
if (readR.compareTo(curR) < 0) {
                        heap.addToTail(readR);
                    } 
else
                        heap.insert(readR);
                }
                readR
=source.readNextRecord();
                
            }
            
//done one run
            mediator.closeRun();
            
            
//prepare for next run
            heap.reverse();
            
while(!heap.isFull()&&!readR.isNull())
            {
                
                heap.insert(readR);
                readR
=source.readNextRecord();
                
            }
            
            
        }
        RecordStore[] stores
=mediator.getProductedStores();
//        LoserTree  lt=new LoserTree(stores);
        WinnerTree  lt=new WinnerTree(stores);
        
        Record least
=lt.nextLeastRecord();
        ra.start();
        
while(!least.isNull())
        {
            ra.acceptRecord(least);
            least
=lt.nextLeastRecord();
        }
        ra.end();
        
        
for(int i=0;i<stores.length;i++)
        {
            stores[i].destroy();
        }
    }
    
    
    
public static void main(String[] args) throws IOException
    {
//        RecordStore store=new MemRecordStore(60004,true);
//        RunAcceptor mediator=new MemRunAcceptor();
//        ResultAcceptor ra=new MemResultAcceptor();
        ExternalSorter sorter=new ExternalSorter();
            
        RecordStore store
=new FileRecordStore("test_sort.txt");
        RunAcceptor mediator
=new FileRunAcceptor("test_sort");
        ResultAcceptor ra
=new FileRecordStore("test_sorted.txt");
        
        
        sorter.sort(
70000, store, mediator, ra);
    }
    
}

其余的都打包在此!

源码

posted @ 2007-12-16 08:08 DoubleH 阅读(3339) | 评论 (3)编辑 收藏

六。 最小支撑树MST
给定一个简单有向图,要求权值最小的生成树,即求最小支撑树问题。
所谓生成树,就是说树的顶点集合等于给定图的顶点集合,且边集合包含于图的边集合。
也就说找出构成树的,经过所有顶点的,且权值最小的边集。
树的定义是要求无回路的,然后是要求连通的。

有两个比较经典的算法是:
1)Prim算法: 该算法的思想跟Dijstra算法非常相似,Dijstra算法中每次求出下一个顶点时依据的是离初始顶点最近的,而Prim算法则找离V1整个集合最近的,也就是从V1中某个节点出发到该顶点的边的权值最小。
其原理也是每次找局部最优,最后构成全局最优。
实现如下

@Override
    
public Edge[] prim() {
        MinHeap
<Edge> heap=new MinHeap<Edge>(Edge.class,numEdges);
        Edge[] edges
=new Edge[numVertexes-1];
        
//we start from 0
        int num=0;//record already how many edges;
        int startV=0;
        Arrays.fill(visitTags, 
false);
        Edge e;
        
for(e=firstEdge(startV);isEdge(e);e=nextEdge(e))
        {
            heap.insert(e);
        }
        visitTags[startV]
=true;
        
        
while(num<numVertexes-1&&!heap.isEmpty())//tree's edge number was n-1
        {
            
            e
=heap.removeMin();
        
            startV
=toVertex(e);
            
if(visitTags[startV])
            {
                
continue;
            }
            visitTags[startV]
=true;
            edges[num
++]=e;
            
for(e=firstEdge(startV);isEdge(e);e=nextEdge(e))
            {
                
if(!visitTags[toVertex(e)])//can't add already visit vertex, this may cause cycle
                heap.insert(e);
            }
            
                
            
        }
        
if(num<numVertexes-1)
        {
            
throw new IllegalArgumentException("not connected graph");
        }
        
return edges;
    }

/**
     * A Graph example
     * we mark the vertexes  with 0,1,2,.14 from left to right , up to down
     * S-8-B-4-A-2-C-7-D
     * |   |   |   |   |
     * 3   3   1   2   5
     * |   |   |   |   |
     * E-2-F-6-G-7-H-2-I
     * |   |   |   |   |
     * 6   1   1   1   2
     * |   |   |   |   |
     * J-5-K-1-L-3-M-3-T
     * 
     
*/
    
public static void testPrimMST() {
    

        
        DefaultGraph g
=new DefaultGraph(15);
        g.setEdge(
018);
        g.setEdge(
108);//its a undirected graph
        g.setEdge(124);
        g.setEdge(
214);
        g.setEdge(
232);
        g.setEdge(
322);
        g.setEdge(
347);
        g.setEdge(
437);
        
        g.setEdge(
053);
        g.setEdge(
503);
        g.setEdge(
163);
        g.setEdge(
613);
        g.setEdge(
271);
        g.setEdge(
721);
        g.setEdge(
382);
        g.setEdge(
832);
        g.setEdge(
495);
        g.setEdge(
945);
        
        
        g.setEdge(
562);
        g.setEdge(
652);
        g.setEdge(
676);
        g.setEdge(
766);
        g.setEdge(
787);
        g.setEdge(
877);
        g.setEdge(
892);
        g.setEdge(
982);
        
        
        g.setEdge(
1056);
        g.setEdge(
5106);
        g.setEdge(
1161);
        g.setEdge(
6111);
        g.setEdge(
1271);
        g.setEdge(
7121);
        g.setEdge(
1381);
        g.setEdge(
8131);
        g.setEdge(
1492);
        g.setEdge(
9142);
        
        g.setEdge(
10115);
        g.setEdge(
11105);
        g.setEdge(
11121);
        g.setEdge(
12111);
        g.setEdge(
12133);
        g.setEdge(
13123);
        g.setEdge(
13143);
        g.setEdge(
14133);
        
        g.assignLabels(
new String[]{"S","B","A","C","D","E","F","G","H","I","J","K","L","M","T"});
        Edge[] edges
=g.prim();
        
int total=0;
        
for(int i=0;i<edges.length;i++)
        {
            System.out.println(edges[i].toString(g));
            total
+=edges[i].getWeight();
        }
        System.out.println(
"MST total cost:"+total);
}

2)Kruskal算法:
该算法开始把,每个节点看成一个独立的两两不同的等价类,每次去权值最小的边,如果关联这条边的两个顶点在同一个等价类里那么这条边不能放入MST(最小生成树)中,否则放入MST中,并把这两个等价类合并成一个等价类。
继续从剩余边集里选最小的边,直到最后剩余一个等价类了。
该算法涉及等价类的合并/查找,一般用父指针树来实现。下面先给出父指针树实现的并查算法。
带路径压缩的算法,其查找时间代价可以看做是常数的。

package algorithms;

/**
 * 
@author yovn
 *
 
*/
public class ParentTree {
    
    
    
private static class PTreeNode
    {
        
int parentIndex=-1;
        
int numChildren=0;//only make sense in root

        
void setParent(int i) {
            
            parentIndex
=i;
            
        }
    }
    PTreeNode[] nodes;
    
int numPartions;
    
public ParentTree(int numNodes)
    {
        nodes
=new PTreeNode[numNodes];
        numPartions
=numNodes;
        
for(int i=0;i<numNodes;i++)
        {
            nodes[i]
=new PTreeNode();
            nodes[i].parentIndex
=-1;//means root
            
        }
        
    }
    
    
/**
     * use path compress
     * 
@param i
     * 
@return
     
*/
    
public int find(int i)
    {
        
if(nodes[i].parentIndex==-1)
        {
            
return i;
        }
        
else
        {
            nodes[i].setParent(find(nodes[i].parentIndex));
//compress the path
            return nodes[i].parentIndex;
        }
    }
    
    
public int numPartions()
    {
        
return numPartions;
    }
    
public boolean union(int i,int j)
    {
        
int pi=find(i);
        
int pj=find(j);
        
if(pi!=pj)
        {
            
if(nodes[pi].numChildren>nodes[pj].numChildren)
            {
                nodes[pj].setParent(pi);
                nodes[pj].numChildren
+=nodes[pi].numChildren;
                nodes[pi].numChildren
=0;
                
            }
            
else
            {
                nodes[pi].setParent(pj);
                nodes[pi].numChildren
+=nodes[pj].numChildren;
                nodes[pj].numChildren
=0;
            }
            numPartions
--;
            
return true;
        }
        
return false;
    }
    
}


从边集里权最小的边,我们又可以借助最小值堆来完成。有了父指针树以及最小值堆,现实Kruskal算法就很简单了:

@Override
    
public Edge[] kruskal() {
        Edge[] edges
=new Edge[numVertexes-1];
        ParentTree ptree
=new ParentTree(numVertexes);
        MinHeap
<Edge> heap=new MinHeap<Edge>(Edge.class,numEdges);
        
for(int i=0;i<numVertexes;i++)
        {
            
for(Edge e=firstEdge(i);isEdge(e);e=nextEdge(e))
            {
                heap.insert(e);
            }
        }
        
int index=0;
        
while(ptree.numPartions()>1)
        {
            Edge e
=heap.removeMin();
            
if(ptree.union(fromVertex(e),toVertex(e)))
            {
                edges[index
++]=e;
            }
        }
        
if(index<numVertexes-1)
        {
            
throw new IllegalArgumentException("Not a connected graph");
        }
        
return edges;
        
    }
OK,到此,图论的大概的算法算是复习完了。

posted @ 2007-12-14 23:48 DoubleH 阅读(3678) | 评论 (1)编辑 收藏

     摘要: 四 拓扑排序 考虑一个任务安排的例子,比如有很多任务T1,T2,.... 这些任务又是相互关联的,比如Tj完成前必须要求Ti已完成,这样T1,T2....序列关于这样的先决条件构成一个图,其中如果Ti必须要先于Tj完成,那么<Ti,Tj>就是该图中的一条路径,路径长度为1的就是一条边。 拓扑排序就是把这些任务按照完成的先后顺序排列出来。显然,这样的顺序可能不是唯一的,比如Tk,T...  阅读全文
posted @ 2007-12-14 21:00 DoubleH 阅读(6414) | 评论 (1)编辑 收藏

     摘要: 很早就想总结一下了,一直没有时间,OK,进入正题。 一 图的基本概念及存储结构 图G是由顶点的有穷集合,以及顶点之间的关系组成,顶点的集合记为V,顶点之间的关系构成边的集合E G=(V,E). 说一条边从v1,连接到v2,那么有v1Ev2(E是V上的一个关系)《=》<v1,v2>∈E. 图有有向图,无向图之分,无向图的一条边相当于有向图的中两条边,即如果无向图...  阅读全文
posted @ 2007-12-14 14:46 DoubleH 阅读(4651) | 评论 (1)编辑 收藏

     摘要: 六 归并排序 算法思想是每次把待排序列分成两部分,分别对这两部分递归地用归并排序,完成后把这两个子部分合并成一个 序列。 归并排序借助一个全局性临时数组来方便对子序列的归并,该算法核心在于归并。 Code highlighting produced by Actipro CodeHighlighter (freeware) http://www.CodeHighlighter.c...  阅读全文
posted @ 2007-12-14 01:03 DoubleH 阅读(15410) | 评论 (11)编辑 收藏

为了便于管理,先引入个基础类:
package algorithms;

/**
 * 
@author yovn
 *
 
*/
public abstract class Sorter<extends Comparable<E>> {
    
    
public abstract void sort(E[] array,int from ,int len);
    
    
public final void sort(E[] array)
    {
        sort(array,
0,array.length);
    }
    
protected final void swap(E[] array,int from ,int to)
    {
        E tmp
=array[from];
        array[from]
=array[to];
        array[to]
=tmp;
    }

}
一 插入排序
该算法在数据规模小的时候十分高效,该算法每次插入第K+1到前K个有序数组中一个合适位置,K从0开始到N-1,从而完成排序:
package algorithms;
/**
 * 
@author yovn
 
*/
public class InsertSorter<extends Comparable<E>> extends Sorter<E> {

    
/* (non-Javadoc)
     * @see algorithms.Sorter#sort(E[], int, int)
     
*/
    
public void sort(E[] array, int from, int len) {
         E tmp
=null;
          
for(int i=from+1;i<from+len;i++)
          {
              tmp
=array[i];
              
int j=i;
              
for(;j>from;j--)
              {
                  
if(tmp.compareTo(array[j-1])<0)
                  {
                      array[j]
=array[j-1];
                  }
                  
else break;
              }
              array[j]
=tmp;
          }
    }
        
    

}

二 冒泡排序
这可能是最简单的排序算法了,算法思想是每次从数组末端开始比较相邻两元素,把第i小的冒泡到数组的第i个位置。i从0一直到N-1从而完成排序。(当然也可以从数组开始端开始比较相邻两元素,把第i大的冒泡到数组的第N-i个位置。i从0一直到N-1从而完成排序。)

package algorithms;

/**
 * 
@author yovn
 *
 
*/
public class BubbleSorter<extends Comparable<E>> extends Sorter<E> {

    
private static  boolean DWON=true;
    
    
public final void bubble_down(E[] array, int from, int len)
    {
        
for(int i=from;i<from+len;i++)
        {
            
for(int j=from+len-1;j>i;j--)
            {
                
if(array[j].compareTo(array[j-1])<0)
                {
                    swap(array,j
-1,j);
                }
            }
        }
    }
    
    
public final void bubble_up(E[] array, int from, int len)
    {
        
for(int i=from+len-1;i>=from;i--)
        {
            
for(int j=from;j<i;j++)
            {
                
if(array[j].compareTo(array[j+1])>0)
                {
                    swap(array,j,j
+1);
                }
            }
        }
    }
    @Override
    
public void sort(E[] array, int from, int len) {
        
        
if(DWON)
        {
            bubble_down(array,from,len);
        }
        
else
        {
            bubble_up(array,from,len);
        }
    }
    
}

三,选择排序
选择排序相对于冒泡来说,它不是每次发现逆序都交换,而是在找到全局第i小的时候记下该元素位置,最后跟第i个元素交换,从而保证数组最终的有序。
相对与插入排序来说,选择排序每次选出的都是全局第i小的,不会调整前i个元素了。
package algorithms;
/**
 * 
@author yovn
 *
 
*/
public class SelectSorter<extends Comparable<E>> extends Sorter<E> {

    
/* (non-Javadoc)
     * @see algorithms.Sorter#sort(E[], int, int)
     
*/
    @Override
    
public void sort(E[] array, int from, int len) {
        
for(int i=0;i<len;i++)
        {
            
int smallest=i;
            
int j=i+from;
            
for(;j<from+len;j++)
            {
                
if(array[j].compareTo(array[smallest])<0)
                {
                    smallest
=j;
                }
            }
            swap(array,i,smallest);
                   
        }

    }
 
}
四 Shell排序
Shell排序可以理解为插入排序的变种,它充分利用了插入排序的两个特点:
1)当数据规模小的时候非常高效
2)当给定数据已经有序时的时间代价为O(N)
所以,Shell排序每次把数据分成若个小块,来使用插入排序,而且之后在这若个小块排好序的情况下把它们合成大一点的小块,继续使用插入排序,不停的合并小块,知道最后成一个块,并使用插入排序。

这里每次分成若干小块是通过“增量” 来控制的,开始时增量交大,接近N/2,从而使得分割出来接近N/2个小块,逐渐的减小“增量“最终到减小到1。

一直较好的增量序列是2^k-1,2^(k-1)-1,.....7,3,1,这样可使Shell排序时间复杂度达到O(N^1.5)
所以我在实现Shell排序的时候采用该增量序列
package algorithms;

/**
 * 
@author yovn
 
*/
public class ShellSorter<extends Comparable<E>> extends Sorter<E>  {

    
/* (non-Javadoc)
     * Our delta value choose 2^k-1,2^(k-1)-1,.7,3,1.
     * complexity is O(n^1.5)
     * @see algorithms.Sorter#sort(E[], int, int)
     
*/
    @Override
    
public void sort(E[] array, int from, int len) {
        
        
//1.calculate  the first delta value;
        int value=1;
        
while((value+1)*2<len)
        {
            value
=(value+1)*2-1;
        
        }
    
        
for(int delta=value;delta>=1;delta=(delta+1)/2-1)
        {
            
for(int i=0;i<delta;i++)
            {
                modify_insert_sort(array,from
+i,len-i,delta);
            }
        }

    }
    
    
private final  void modify_insert_sort(E[] array, int from, int len,int delta) {
          
if(len<=1)return;
          E tmp
=null;
          
for(int i=from+delta;i<from+len;i+=delta)
          {
              tmp
=array[i];
              
int j=i;
              
for(;j>from;j-=delta)
              {
                  
if(tmp.compareTo(array[j-delta])<0)
                  {
                      array[j]
=array[j-delta];
                  }
                  
else break;
              }
              array[j]
=tmp;
          }

    }
}

五 快速排序
快速排序是目前使用可能最广泛的排序算法了。
一般分如下步骤:
1)选择一个枢纽元素(有很对选法,我的实现里采用去中间元素的简单方法)
2)使用该枢纽元素分割数组,使得比该元素小的元素在它的左边,比它大的在右边。并把枢纽元素放在合适的位置。
3)根据枢纽元素最后确定的位置,把数组分成三部分,左边的,右边的,枢纽元素自己,对左边的,右边的分别递归调用快速排序算法即可。
快速排序的核心在于分割算法,也可以说是最有技巧的部分。
package algorithms;

/**
 * 
@author yovn
 *
 
*/
public class QuickSorter<extends Comparable<E>> extends Sorter<E> {

    
/* (non-Javadoc)
     * @see algorithms.Sorter#sort(E[], int, int)
     
*/
    @Override
    
public void sort(E[] array, int from, int len) {
        q_sort(array,from,from
+len-1);
    }

    
    
private final void q_sort(E[] array, int from, int to) {
        
if(to-from<1)return;
        
int pivot=selectPivot(array,from,to);

        
        
        pivot
=partion(array,from,to,pivot);
        
        q_sort(array,from,pivot
-1);
        q_sort(array,pivot
+1,to);
        
    }


    
private int partion(E[] array, int from, int to, int pivot) {
        E tmp
=array[pivot];
        array[pivot]
=array[to];//now to's position is available
        
        
while(from!=to)
        {
            
while(from<to&&array[from].compareTo(tmp)<=0)from++;
            
if(from<to)
            {
                array[to]
=array[from];//now from's position is available
                to--;
            }
            
while(from<to&&array[to].compareTo(tmp)>=0)to--;
            
if(from<to)
            {
                array[from]
=array[to];//now to's position is available now 
                from++;
            }
        }
        array[from]
=tmp;
        
return from;
    }


    
private int selectPivot(E[] array, int from, int to) {
    
        
return (from+to)/2;
    }

}

还有归并排序,堆排序,桶式排序,基数排序,下次在归纳。

posted @ 2007-12-13 01:08 DoubleH 阅读(36708) | 评论 (15)编辑 收藏

/**
 * 
 
*/

import java.util.Stack;
import java.util.Vector;

/**
 * 
@author yovn
 *
 
*/
public class TreeDemo {
    
    
static interface NodeVistor
    {
         
<T> void visit(BinaryTreeNode<T> node);
    }
    
static class BinaryTree<T>
    {
        BinaryTreeNode
<T> root;
        
        
public BinaryTree(BinaryTreeNode<T> root) {
            
this.root=root;
        }

        
//no recursion ,pre-order
        void NLRVisit(NodeVistor visitor)
        {
            BinaryTreeNode
<T> pointer=root;
            Stack
<BinaryTreeNode<T>> stack=new Stack<BinaryTreeNode<T>>();
            
while(!stack.isEmpty()||pointer!=null)
            {
                
if(pointer!=null)
                {
                    visitor.visit(pointer);
                    
if(pointer.rightChild!=null)
                    {
                        stack.push(pointer.rightChild);
                    }
                    pointer
=pointer.leftChild;
                }
                
//go to right child
                else
                {
                    pointer
=stack.pop();
                    
                }
            }
        }
        
        
//no recursion , in-order
        void LNRVisit(NodeVistor visitor)
        {
            BinaryTreeNode
<T> pointer=root;
            Stack
<BinaryTreeNode<T>> stack=new Stack<BinaryTreeNode<T>>();
            
while(!stack.isEmpty()||pointer!=null)
            {
                
if(pointer!=null)
                {
                    stack.push(pointer);
                    
                    pointer
=pointer.leftChild;
                }
                
//no left child here, then visit root and then go to right child
                else
                {
                    pointer
=stack.pop();
                    visitor.visit(pointer);
                    pointer
=pointer.rightChild;
                    
                }
            }
        }
        
        
        
//no recursion ,post-order,this one is the most complex one.
        
//we need know from which side ,it back(left or right)
        void LRNVisit(NodeVistor visitor)
        {
            
if(root==null)return;
            BinaryTreeNode
<T> pointer=root;
            Stack
<BinaryTreeNode<T>> stack=new Stack<BinaryTreeNode<T>>();
            
while(true)
            {
                
                
//mark left 
                while(pointer!=null)
                {
                    stack.push(pointer);
                    pointer
=pointer.leftChild;
                }
                
                
                pointer
=stack.pop();
                
                
while(pointer.visitedRight)//back from right child, so we can visit it now.
                {
                    visitor.visit(pointer);
                    
if(stack.isEmpty())return;
                    pointer
=stack.pop();
                }
            
                pointer.visitedRight
=true;
                stack.push(pointer);
                
                pointer
=pointer.rightChild;
                
                
            }
            
        }
        
        
        
void levelOrder(NodeVistor visitor)
        {
            
if(root==null)return;
            BinaryTreeNode
<T> pointer=root;
            Vector
<BinaryTreeNode<T>> queue=new Vector<BinaryTreeNode<T>>();
            
            queue.add(pointer);
            
while(!queue.isEmpty())
            {
                BinaryTreeNode
<T> node=queue.remove(0);
                visitor.visit(node);
                
if(node.leftChild!=null)
                {
                    queue.add(node.leftChild);
                }
                
if(node.rightChild!=null)
                {
                    queue.add(node.rightChild);
                }
                
            }
            
        }
        
    }
    
static class BinaryTreeNode<T>
    {
        
        BinaryTreeNode(T data)
        {
            
this.data=data;
        }
        T data;
        
boolean visitedRight;
        BinaryTreeNode
<T> leftChild;
        BinaryTreeNode
<T> rightChild;
    }

    
/**
     * 
     
*/
    
public TreeDemo() {
        
// TODO Auto-generated constructor stub
    }

    
/**
     * 
@param args
     
*/
    
public static void main(String[] args) {
        BinaryTreeNode
<String> root=new BinaryTreeNode<String>("A");
        root.leftChild
=new BinaryTreeNode<String>("B");
        root.rightChild
=new BinaryTreeNode<String>("C");
        
        
        root.leftChild.leftChild
=new BinaryTreeNode<String>("D");
        
        root.rightChild.leftChild
=new BinaryTreeNode<String>("E");
        
        root.rightChild.rightChild
=new BinaryTreeNode<String>("F");
        
        root.rightChild.leftChild.rightChild
=new BinaryTreeNode<String>("G");
        
        root.rightChild.rightChild.leftChild
=new BinaryTreeNode<String>("H");
        root.rightChild.rightChild.rightChild
=new BinaryTreeNode<String>("I");
        
        NodeVistor visitor
=new NodeVistor()
        {

            @Override
            
public <T> void visit(BinaryTreeNode<T> node) {
                System.out.print(
"'"+node.data+"'");
                
            }
            
        };
        
        BinaryTree
<String> tree=new BinaryTree<String>(root);

        
        System.out.println(
"pre-order visit");
        tree.NLRVisit(visitor);
        System.out.println();
        System.out.println(
"in-order visit");
        
        tree.LNRVisit(visitor);
        
        System.out.println();
        System.out.println(
"post-order visit");
        
        tree.LRNVisit(visitor);
        
        System.out.println();
        System.out.println(
"level-order visit");
        
        tree.levelOrder(visitor);
    }

}
posted @ 2007-10-11 16:05 DoubleH 阅读(840) | 评论 (0)编辑 收藏

/**
 * 
 
*/
package com.yovn.algo;

import java.util.Stack;
import java.util.Vector;

/**
 * 
@author yovn
 *
 
*/
public class Caculator {

    
    
class Item
    {
        
boolean ops;
        
int value;
        
        Character opVal;
        
int opPriority;
    }
    
    Stack
<Item> opStack=new Stack<Item>();
    Vector
<Item> calcStack=new Vector<Item>();
    
/**
     * 
     
*/
    
public Caculator() {
        
// TODO Auto-generated constructor stub
    }
    
    
    
    
    
public int calc()
    {
        Stack
<Item> tmp=new Stack<Item>();
        
while(!calcStack.isEmpty())
        {
            Item it
=calcStack.remove(0);
            
            
if(!it.ops)
            {
                tmp.push(it);
            }
            
else
            {
                
int op2=tmp.pop().value;
                
int op1=tmp.pop().value;
                Item newItem
=new Item();
                newItem.ops
=true;
                
switch(it.opVal)
                {
                
case '+':
                    newItem.value
=op1+op2;
                    
                    
break;
                
case '-':
                    newItem.value
=op1-op2;
                    
break;
                
case '*':
                    
                    newItem.value
=op1*op2;
                    
break;
                
case '/':
                    newItem.value
=op1/op2;
                    
break;
                }
                tmp.push(newItem);
            }
        }
        
return tmp.pop().value;
    }
    
/**
     * 1)数字直接输出
     * 2)开括号则压栈
     * 3)闭括号把栈中元素依次输出直到遇到开括号
     * 4)运算符时
     *     a)循环,当栈非空,并且栈顶元素不是开括号,并且栈顶运算符优先级不低于输入的运算符的优先级,反复将其输出
     *     b)把输入运算符压栈
     * 5)输出栈内剩余元素
     * 
@param in
     * 
@return
     
*/
    
public String transInfixToPosfix(String in)
    {
        
char[] cin=in.toCharArray();
        StringBuffer buffer
=new StringBuffer();
       
        
for(int i=0;i<cin.length;i++)
        {
            Item newItem
=new Item();
            newItem.opPriority
=1;
            newItem.ops
=false;
            
            
switch(cin[i])
            {
            
            
case '+':
                newItem.opPriority
=1;
                newItem.ops
=true;
                newItem.opVal
='+';
                doOps(buffer, newItem);
                
                
break;
            
case '-':
                newItem.opPriority
=1;
                newItem.ops
=true;
                newItem.opVal
='-';
                doOps(buffer, newItem);
                
break;
            
case '*':
                newItem.opPriority
=2;
                newItem.ops
=true;
                newItem.opVal
='*';
                doOps(buffer, newItem);
                
break;
            
case '/':
                newItem.opPriority
=2;
                newItem.ops
=true;
                newItem.opVal
='/';
                doOps(buffer, newItem);
                
break;
                
            
case '(':
                newItem.ops
=true;
                newItem.opVal
='(';
                opStack.push(newItem);
                
                
break;
            
case ')':
                
boolean meetClose=false;
                
while(!opStack.isEmpty())
                {
                    Item item
=opStack.peek();
                    
if(item.ops&&item.opVal!='(')
                    {
                        calcStack.add(item);
                        opStack.pop();
                        buffer.append(item.opVal);
                    }
                    
else if(item.ops)
                    {
                        opStack.pop();
                        meetClose
=true;
                        
break;
                    }
                }
                
if(!meetClose)
                {
                    
throw new RuntimeException();
                }
                
break;
                
            
default:
                
int j=i;
                
for(;j<cin.length&&cin[j]>='0'&&cin[j]<='9';j++);
                
if(j==i)
                {
                    
throw new RuntimeException("wrong input.");
                }
                newItem.ops
=false;
                newItem.value
=Integer.parseInt(new String(cin,i,j-i));
                buffer.append(newItem.value);
                calcStack.add(newItem);
                i
=j-1;
                
break;
                
                
            }
        }
        
while(!opStack.isEmpty())
        {
            Item item
=opStack.pop();
            calcStack.add(item);
            buffer.append(item.opVal);
            
        }
        
return buffer.toString();
        
    }



    
private void doOps(StringBuffer buffer, Item newItem) {
        
while(!opStack.isEmpty())
        {
            Item item
=opStack.peek();
            
if(item.opVal!='('&&item.opPriority>=newItem.opPriority)
            {
                calcStack.add(item);
                opStack.pop();
                buffer.append(item.opVal);
            }
            
else
            {
                
break;
            }
        }
        opStack.push(newItem);
    }
    

    
/**
     * 
@param args
     
*/
    
public static void main(String[] args) {
        Caculator calc
=new Caculator();
        
        System.out.println(
"1+2*3+7-(4/2+8)/5="+calc.transInfixToPosfix("1+2*3+7-(4/2+8)/5"));
        System.out.println(
"value is:"+calc.calc());

    }

}
posted @ 2007-10-09 22:48 DoubleH 阅读(995) | 评论 (1)编辑 收藏

算法:

设G是带权图,图中的顶点多于一个,且所有的权都为正数。本算法确定从顶点S到G中其他各个顶点的距离和最短通路。在本算法中P表示带永久标记的顶点的集合。顶点A的前驱是P中的一个顶点,用来标记A。顶点U和V之间的边的权重用W(U,V)表示,如果U和V之间没有边,则记作W(U,V)=∞.

步骤1 (对S做标记)

      (a)将S标记为0,并使S没有前驱

      (b)令P={S}

步骤2 (对其他顶点作标记)

      将每个不在P中的顶点V标记为W(S,V)(可能是暂时的),并使V的前驱为S(可能是暂时的)

步骤3 (扩大P,修改标记)

     Repeat

     步骤3.1 (是另一个标记永久化)

                  把不在P中且带有最小标记的顶点U加入到P中去(如果这样的顶点有多个则任选其中一个)

    步骤3.2  (修改临时标记)

                对每个不在P中并且和U相邻的顶点X,把X的标记替换为下列这两者中的较小者:i)X的旧标记,ii)U上的标记与W(U,X)之和。如果X的标记改变了,则使U成为X的新前驱(可能是暂时的)

    Until P包含G中的每一个顶点

步骤4 (求出距离和最短通路)

   顶点Y上的标记是从S到Y的距离。如果Y上的标记是∞,那么从S到Y就没有通路,从而

没有最短通路;否则,按照下列序列的逆序使用顶点就构成从S到Y的一条最短通路:

Y,Y的前驱,Y的前驱的前驱,。。。。,直至S

 

 

证明:Dijkstra算法给出了从S到G的各个顶点的最短通路长度。

 

我们假设G中的每个顶点V都被赋予了一个标记L(V),它要么是一个数,要么是∞。假设P是G的顶点的集合,P包含S,满足:

1)如果V属于P,则L(V)是从S到V的最短通路的长度,并且存在这样的从S到V的最短通路:通路上的顶点都在P中

2)如果V不属于P,则L(V)是从S到V的满足下面限制的最短通路的长度:V是通路中唯一一个不属于P的顶点。

 

我们可以用归纳法证明Dijkstra算法中的P符合上述定义的集合:

1)当P中元素个数为1时,P对应算法中的第一步,P={S},显然满足。

2)假设P中元素个数为K时,P满足上述定义,下面看算法的的第三步,

   先找出不在P中且带有最小标记的顶点U,标记为L(U), 可以证明从S到U的最短通路中除U外不包含不属于P的元素。

因为若存在除U外其他顶点,则最短通路为SP1P2...PnQ1Q2...QnU(P1,P2..Pn属于P,Q1,Q2,...Qn不属于P),则由性质2)最短通路长度为L(Q1)+PATH(Q1,U)>L(U)

从而大于SP1P2..PnU的通路长度L(U),不是最短通路,所以从S到U的最短通路中除U外不包含不属于P的元素,从而从S到U的最短通路长度由L(U)给出.

现把U加入P中构成P' ,显然P'满足性质1)。

取V不属于P',显然V也不属于P,那么从S到V的最短通路且满足除V外所有顶点都在P'中的通路有两种可能,i)包含U,ii)不包含U。

对i)SP1P2...PnUV=L(U)+W(U,V)

   ii)SP1P2..PnV=L(V)

显然二者中的最小给出了从S到V的最短通路且满足除V外所有顶点都在P'中的长度。

从而算法第三步给出的P'含K+1个元素且满足1),2)。

又归纳,命题得证!

 

下面是一个Java版的实现:最短路径的Java实现

posted @ 2007-09-07 13:24 DoubleH 阅读(6232) | 评论 (3)编辑 收藏

     摘要: 这周末看不进书了,于是完善了以前的Java转EXE工具
以前的工具运行时要把所有的class载入,这对于大点的项目是不合适的。
这个版本调整了一下Loader的机制,保持EXE跟类文件浑然一体的同时又可以延迟加载class.
另外这个版本的加密强度提高很多,用来代替那些class混淆软件应该也不错。:)  阅读全文
posted @ 2007-07-15 23:32 DoubleH 阅读(2445) | 评论 (9)编辑 收藏

仅列出标题
共5页: 上一页 1 2 3 4 5 下一页