Пример #1
0
        private PrimeNode Contraction(SplitTree ST, SplitTree tPrime, int xId)
        {
            //during the contraction, the active flags won't be used any more. thus available as temporary delete flags
            //when a deleted node has non-empty parentLink and empty unionFind_parent, it is a degenerate to prime conversion and the parentLink points to the converted prime node.
            //when a deleted node has non-empty unionFind_parent, it is a fake node (only playing a role of child representative)
            ST.ResetActiveFlags();
            List<DegenerateNode> Phase1List = new List<DegenerateNode>();
            List<Node> Phase2List = new List<Node>();
            List<Node> nonLeafChildren = new List<Node>();
            Node phase3 = null;//since phase 3 is recursive, we need only a start point.
            #region Phase 0 Initial sweep
            foreach (var v in tPrime.vertices)
            {
                var d = v as DegenerateNode;
                var n = v as Node;
                if (d != null && d.isStar && d.rootMarkerVertex == d.center)
                    Phase1List.Add(d);
                if (n != null && n.Degree(n.rootMarkerVertex) == 1)
                    Phase2List.Add(n);
                if (n != null)
                    phase3 = n;//in case Phase1List and Phase2List are both empty, at least we have a start point for phase 3
            }
            #endregion
            #region Phase 1 node-joins
            foreach (var star in Phase1List)
            {
                if (star.active)//deleted
                    continue;
                phase3 = star;
                nonLeafChildren.Clear();
                phase3.ForEachChild((v) =>
                    {
                        if (v is Node)
                        {
                            nonLeafChildren.Add(v as Node);
                        }
                        return IterationFlag.Continue;
                    }, subtree: true);
                foreach (var c in nonLeafChildren)
                {
                    phase3 = NodeJoin(ST, phase3, c);
                    //c.parentLink = dummy;
                }
                phase3.visited = true;//add the joint node back into T'
            }
            #endregion
            #region Phase 2 node-joins
            foreach (var node in Phase2List)
            {
                if (node.active)//actually I mean "deleted"
                    continue;
                phase3 = node;
                var p = phase3.parent;
                if (p.visited && p is Node)
                {
                    phase3 = NodeJoin(ST, p as Node, phase3);//make sure phase3 now points to the new parent(which is prime)
                }
            }
            #endregion
            #region Phase 3 node-joins
            Debug.Assert(phase3 != null, "Phase 3 node is null, which means that there's nothing left in the fully-mixed subtree T'");
            while (true)
            {
                while (true)
                {
                    nonLeafChildren.Clear();
                    phase3.ForEachChild((v) =>
                        {
                            if (v is Node)
                            {
                                nonLeafChildren.Add(v as Node);
                            }
                            return IterationFlag.Continue;
                        }, subtree: true);
                    if (nonLeafChildren.Count == 0)
                        break;
                    foreach (var c in nonLeafChildren)
                    {
                        phase3 = NodeJoin(ST, phase3, c);
                    }
                }
                var p = phase3.parent;
                if (p == null || p is Leaf || p.visited == false)
                {
                    break;
                }
                else
                    phase3 = p as Node;
            }
            #endregion
            //rebuild ST from dummy flags. Note that this step is very important before using Find() and parent accessor again, because there might be a node with unionFind_parent == dummyFake, and dummyFake has unionFind_parent == null
            //List<GLTVertex> newSTList = new List<GLTVertex>();
            //foreach (var vertex in ST.vertices)
            //{
            //    if (!vertex.active)
            //        newSTList.Add(vertex);//a normal vertex
            //    else if (vertex.parentLink != null && vertex.unionFind_parent == null)
            //        newSTList.Add(vertex.parentLink);//a converted vertex
            //    //otherwise, either a fake node, or a truely-removed one, we don't add them back to ST any more.
            //    //if (vertex.parentLink != deleteDummy && vertex.unionFind_parent != fakeDummy)//neither deleted nor fake
            //    //    newSTList.Add(vertex);
            //    //else if (vertex.parentLink == deleteDummy && vertex.unionFind_parent != null)//replaced
            //    //    newSTList.Add(vertex.unionFind_parent);
            //    //else if (vertex.unionFind_parent == fakeDummy)
            //    //    vertex.unionFind_parent = vertex;//point the unionFind_parent back
            //}
            //ST.vertices = newSTList;

            HashSet<MarkerVertex> Pset = new HashSet<MarkerVertex>();
            phase3.ForEachMarkerVertex((v) =>
                {
                    if (v.perfect)
                        Pset.Add(v);
                    return IterationFlag.Continue;
                });
            Leaf newLeaf = new Leaf()
            {
                id = xId,
                parent = phase3,
            };
            MarkerVertex newMarker = new MarkerVertex()
            {
                opposite = newLeaf,
            };
            newLeaf.opposite = newMarker;
            (phase3 as PrimeNode).AddMarkerVertex(newMarker, Pset);
            (phase3 as PrimeNode).lastMarkerVertex = newMarker;
            ST.AddLeaf(newLeaf);
            return phase3 as PrimeNode;
        }
        //XXX this algorithm may terminate when there's still an active vertex.
        private SplitTree SmallestSpanningTree(SplitTree ST, int x)
        {
            SplitTree ret = new SplitTree();//Here we don't need the associated graph, just a tree.
            if (ST.vertices.Count == 0)
                return ret;
            //Compute N(x). Note that the initial set L is also Nx
            //PerfectFlags are reset in Algorithm 5, which calls this one.
            Queue<GLTVertex> L = new Queue<GLTVertex>();
            ST.ResetActiveFlags();
            ST.ResetNeighborFlags();
            var originalNx = storage[x];
            GLTVertex p = null;
            bool rootVisited = false;
            foreach (int n in originalNx)
            {
                Leaf v = null;
                if (ST.LeafMapper.TryGetValue(n, out v))
                {
                    v.active = true;//marking a vertex with active means that it is currently enqueued
                    (v as Leaf).neighbor = true;
                    //set the non-root marker vertices opposite leaves of N(x) to perfect
                    var opposite = (v as Leaf).opposite as MarkerVertex;
                    //if (opposite.node == null)//non-root
                    {
                        opposite.perfect = true;
                    }
                    L.Enqueue(v);
                }
            }
            ST.ResetVisitFlags();
            while (L.Count > 0
                //(!rootVisited && L.Count >= 2) || (rootVisited && L.Count >= 1)
                )
            {
                var u = L.Dequeue();
                u.active = false;
                u.visited = true;
                ret.vertices.Add(u);
                p = u.parent;
                if (p == null)
                    rootVisited = true;
                else if (!p.visited && !p.active)
                {
                    p.active = true;
                    L.Enqueue(p);
                }
            }
            if (ret.vertices.Count == 0)
                return ret;
            //adjust the root
            GLTVertex root = ret.vertices[0];
            while ((p = root.parent) != null && p.visited)
                root = p;
            //do not use numberOfChildren, since not all of the children are included in the subtree
            while (true)
            {
                if (root is Leaf)//if root is a leaf, then definitely it has less than 2 children. proceed to the child if it has one.
                {
                    var opposite = (root as Leaf).opposite;
                    bool rootInNx = (root as Leaf).neighbor;
                    if (opposite == null)
                    {
                        //The current leaf is the only vertex in the GLT.
                        //If it is not in Nx, drop it
                        if (!rootInNx)
                        {
                            root.visited = false;
                            ret.vertices.Remove(root);
                            root = null;
                        }
                        break;
                    }

                    if (rootInNx)
                        break;
                    var marker = opposite as MarkerVertex;
                    Debug.Assert(marker != null, "The opposite of a leaf is something other than MarkerVertex!");
                    //Since we are traversing from parent to children, the opposite marker vertex must be the root marker vertex
                    ret.vertices.Remove(root);
                    root.visited = false;
                    root = marker.node;
                }
                else//root is a node. then we check each of its marker vertex except the root marker, find its opposite and see whether it's included or not
                {
                    int count = 0;
                    GLTVertex child = null;
                    (root as Node).ForEachChild((v) =>
                        {
                            ++count;
                            child = v;
                            return IterationFlag.Continue;
                        }, true);
                    if (count != 1)
                        break;
                    //remember to remove root from ret and uncheck its visited flag before iterating to the child
                    ret.vertices.Remove(root);
                    root.visited = false;
                    root = child;
                }
                //ret.vertices.Remove(root);
                //root = c;
            }
            ret.root = root;

            return ret;
        }