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로 할당한다. } }
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; }