public void Enqueue(PQNode <ElementType> newNode)     // 노드 삽입 메소드.
        {
            int currentPosition = usedSize;                   // currentPosition을 usedSize 위치(마지막 노드의 위치 + 1)로 지정.
            int parentPosition  = GetParent(currentPosition); // parentPosition을 currentPosition의 부모 위치로 지정.

            if (usedSize == capacity)                         // 만약 큐가 가득 찼을 경우.
            {
                if (capacity == 0)                            // 용량이 0인 경우,
                {
                    capacity = 1;                             // 용량을 1로 늘린다.
                }
                capacity *= 2;                                // 용량을 2배로 늘린다.
                Array.Resize(ref nodes, capacity);            // 바뀐 크기에 맞게 배열을 재할당.
            }

            nodes[currentPosition] = new PQNode <ElementType>(newNode);                                     // 현재 위치의 노드에 삽입할 노드(인자)를 복사한다.

            while (currentPosition > 0 && nodes[currentPosition].Priority < nodes[parentPosition].Priority) // 현재 위치가 0보다 크면서(위치가 0일 경우 깊이가 0이면서 우선순위가 가장 높은 노드이다.) 우선순위가 부모 노드보다 높을 경우,
            {                                                                                               // 높은 우선 순위에 따라 힙 정렬을 수행하여 트리를 재구성한다.
                SwapNodes(currentPosition, parentPosition);                                                 // 현재 노드와 부모 노드의 위치를 맞바꾼다.

                currentPosition = parentPosition;                                                           // 현재 위치를 부모의 위치로 옮김.
                parentPosition  = GetParent(currentPosition);                                               // 현재 위치를 기준으로 다시 부모 위치를 구하여 지정한다.
            }

            usedSize++; // 노드가 하나 추가되었으므로 사용량을 1 늘린다.
        }
        public void SwapNodes(int index1, int index2)                            // 두 노드의 위치를 맞바꾸는 메소드.
        {
            PQNode <ElementType> temp = new PQNode <ElementType>(nodes[index1]); // 임시 객체에 index1을 복사한다.

            nodes[index1] = new PQNode <ElementType>(nodes[index2]);             // index1에 index2를 복사한다.
            nodes[index2] = new PQNode <ElementType>(temp);                      // index2에 임시 객체를 복사한다.
        }
        public void Dequeue(out PQNode <ElementType> root)                           // 노드 삭제 메소드.
        {
            int parentPosition = 0;                                                  // 부모 노드의 위치 변수 선언.

            root     = new PQNode <ElementType>(nodes[0]);                           // 우선 순위가 가장 높은 노드(priority 값이 낮은 노드)를 root에 복사하여 반환한다.
            nodes[0] = new PQNode <ElementType>(default(int), default(ElementType)); // 삭제된 노드의 모든 필드를 기본값으로 초기화한다. (사용하지 않는 노드이므로 필드 값을 비워줌.)

            usedSize--;                                                              // usedSize를 1 낮춘다(이로써 usedSize는 마지막 노드의 위치 값이다.).
            SwapNodes(0, usedSize);                                                  // 사용하지 않는 첫번째 노드(인덱스 0)를 마지막 노드와 맞바꾼다.

            int leftPosition  = GetLeftChild(0);                                     // 바뀐 첫번째 노드(마지막에 있던 노드)의 왼쪽 자식 위치를 leftPosition으로 할당한다.
            int rightPosition = leftPosition + 1;                                    // leftPosition + 1(오른쪽 자식 노드 위치)의 값을 rightPosition로 할당한다.

            while (true)                                                             // 무한 루프.
            {                                                                        // 높은 우선 순위에 따라 힙 정렬을 수행하여 트리를 재구성한다.
                int selectedChild = 0;                                               // selectedChild(기준 노드의 위치) 변수를 선언한다.

                if (leftPosition >= usedSize)                                        // 왼쪽 자식 노드가 사용 범위 밖일 경우(usedSize와 같거나 보다 클 경우),
                {
                    break;                                                           // 루프를 빠져나간다.
                }
                if (rightPosition >= usedSize)                                       // 왼쪽 자식 노드가 사용 범위 안이면서 오른쪽 자식 노드는 밖일 경우,
                {
                    selectedChild = leftPosition;                                    // 왼쪽 자식의 위치를 selectedChild로 할당한다.
                }
                else // 오른쪽 자식 노드도 사용 범위 안일 경우,
                {
                    if (nodes[leftPosition].Priority > nodes[rightPosition].Priority) // 왼쪽 자식 노드의 우선순위가 오른쪽 자식 노드보다 낮은 경우,
                    {
                        selectedChild = rightPosition;                                // 오른쪽 자식 노드의 위치를 selectedChild로 할당한다.
                    }
                    else // 왼쪽 자식 노드의 우선 순위가 오른쪽 자신 노드와 같거나 보다 높을 경우,
                    {
                        selectedChild = leftPosition; // 왼쪽 자식 노드의 위치를 selectedChild로 할당한다.
                    }
                }

                if (nodes[selectedChild].Priority < nodes[parentPosition].Priority) // selectedChild 위치의 우선순위가 부모(처음 parentPosition의 값은 0이다.) 노드보다 높을 경우.
                {
                    SwapNodes(parentPosition, selectedChild);                       // selectedChild 위치의 노드와 그 부모 노드를 맞바꾼다.
                    parentPosition = selectedChild;                                 // 부모 노드의 위치를 selectedChild 위치로 바꾼다.
                }
                else // selectedChild 위치의 우선순위가 부모 노드와 같거나 보다 낮을 경우,
                {
                    break;                                    // 루프를 빠져나간다.
                }
                leftPosition  = GetLeftChild(parentPosition); // 바뀐 부모 노드의 왼쪽 자식 노드 위치를 leftPosition에 할당한다.
                rightPosition = leftPosition + 1;             // leftPosition + 1(오른쪽 자식 노드 위치)의 값을 rightPosition로 할당한다.
            }
        }
Esempio n. 4
0
        public void Kruskal(Graph <ElementType> mst)                                                                          // 크루스칼 알고리즘 메소드.
        {
            Vertex <ElementType>[] mstVertices = new Vertex <ElementType> [vertexCount];                                      // 현재 그래프의 정점 수만큼 최소 신장 트리(MST)의 정점 배열을 선언.
            DisjointSet <Vertex <ElementType> >[] vertexSet = new DisjointSet <Vertex <ElementType> > [vertexCount];          // 정점 수 만큼 분리 집합 배열을 선언.

            PriorityQueue <Edge <ElementType> > pq = new PriorityQueue <Edge <ElementType> >(10);                             // 우선순위 큐를 선언, 크기는 10으로 임의 지정한다.

            int i = 0;                                                                                                        // 반복문을 수행하기 위해 i는 0으로 초기화.
            Vertex <ElementType> currentVertex = vertices;                                                                    // 현재 정점을 나타내는 변수를 선언, 해당 그래프의 첫번째 정점으로 할당한다.

            while (currentVertex != null)                                                                                     // 현재 정점이 null이 될 때까지 반복한다.
            {
                vertexSet[i]   = new DisjointSet <Vertex <ElementType> >(currentVertex);                                      // i번째 집합 배열에 현재 정점 집합을 할당한다.
                mstVertices[i] = new Vertex <ElementType>(currentVertex.Data);                                                // i번째 MST 정점에 현재 정점을 복사한다.
                mst.AddVertex(mstVertices[i]);                                                                                // MST 그래프에 i번째 MST 정점을 추가한다.

                Edge <ElementType> currentEdge = currentVertex.AdjacencyList;                                                 // 현재 간선을 현재 정점의 첫번째 인접 리스트로 할당한다.
                while (currentEdge != null)                                                                                   // 현재 간선이 null이 될 때까지 반복.
                {
                    PQNode <Edge <ElementType> > newNode = new PQNode <Edge <ElementType> >(currentEdge.Weight, currentEdge); // 현재 간선의 가중치를 우선순위 값으로, 현재 간선 객체를 데이터로, 우선순위 큐 노드를 생성한다.
                    pq.Enqueue(newNode);                                                                                      // 생성한 노드를 큐에 Enqueue한다.

                    currentEdge = currentEdge.Next;                                                                           // 다음 간선을 현재 간선으로 지정한다.
                }

                currentVertex = currentVertex.Next; // 다음 정점을 현재 정점으로 지정한다.
                i++;                                // i 값을 1 증가시킨다.
            }

            while (!pq.IsEmpty())                                    // 큐가 빌 때까지 반복.
            {
                pq.Dequeue(out PQNode <Edge <ElementType> > popped); // Dequeue한 큐의 노드를 popped 노드에 복사한다.
                Edge <ElementType> currentEdge = popped.Data;        // popped 노드 데이터(간선)를 currentEdge에 할당한다.
                Console.WriteLine("{0} - {1} : {2}", currentEdge.From.Data, currentEdge.Target.Data, currentEdge.Weight);

                int fromIndex = currentEdge.From.Index;                                                                                                     // 현재 간선 정보 중 시발 정점의 Index 값을 fromIndex에 할당한다.
                int toIndex   = currentEdge.Target.Index;                                                                                                   // 현재 간선 정보 중 종발 정점의 Index 값을 toIndex에 할당한다.

                if (DisjointSet <Vertex <ElementType> > .FindSet(vertexSet[fromIndex]) != DisjointSet <Vertex <ElementType> > .FindSet(vertexSet[toIndex])) // 시발 정점의 집합과 종발 정점의 집합이 다를 경우,
                {
                    mstVertices[fromIndex].AddEdge(new Edge <ElementType>(mstVertices[fromIndex], mstVertices[toIndex], currentEdge.Weight));               // MST 그래프에서 시발 정점의 인접리스트에 현재 간선을 추가한다.

                    mstVertices[toIndex].AddEdge(new Edge <ElementType>(mstVertices[toIndex], mstVertices[fromIndex], currentEdge.Weight));                 // MST 그래프에서 종발 정점의 인접리스트에 현재 간선을 추가한다.

                    vertexSet[fromIndex].UnionSet(vertexSet[toIndex]);                                                                                      // 시발 정점의 집합에 종발 정접의 집합을 합한다.
                }
            }
        }
 public PQNode(PQNode <ElementType> pqNode) // 복사 생성자.
 {
     priority = pqNode.priority;
     data     = pqNode.data;
 }