Skip to content
This repository was archived by the owner on Feb 28, 2023. It is now read-only.

Commit d46a3a2

Browse files
committed
added kruskal's algorithm
1 parent 9a11930 commit d46a3a2

File tree

9 files changed

+130
-59
lines changed

9 files changed

+130
-59
lines changed

README.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,21 @@ You should be able to find a live-demo [here](https://mattmoony.github.io/pretty
1818
* [x] Controls
1919
* [x] Algorithm Selection
2020
* [x] Speed control
21-
* [ ] Algorithms
21+
* [x] Algorithms
2222
* [x] Depth-First-Search
2323
* [x] Breadth-First-Search
2424
* [x] Dijkstra's Algorithm
2525
* [x] A* Algorithm
2626
* [x] Prim's Algorithm
27-
* [ ] Kruskal's Algorithm
27+
* [x] Kruskal's Algorithm
2828
* [x] Core
2929
* [x] Classes
3030
* [x] Graph
3131
* [x] Node
32+
* [x] Edge
3233
* [x] Canvas
3334
* [x] PriorityQueue
3435
* [x] Interfaces
35-
* [x] Edge
3636
* [x] Pair
3737

3838
---

index.html

-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
<meta name="viewport" content="width=device-width, initial-scale=1.0">
66
<title>Pretty-Graph-Algorithms</title>
77
<link type="text/css" rel="stylesheet" href="style/index.css" />
8-
<script src="https://kit.fontawesome.com/eeafe44cad.js" crossorigin="anonymous"></script>
98
</head>
109
<body>
1110
<h1>Pretty Graph Algorithms</h1>

scss/index.scss

+5-3
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ html, body {
2626
flex-direction: column;
2727
justify-content: stretch;
2828
align-items: stretch;
29-
width: 60%;
30-
height: 60%;
29+
width: 65%;
30+
height: 65%;
3131

3232
& > div:first-child {
3333
flex-grow: 1;
@@ -119,10 +119,12 @@ html, body {
119119
}
120120
}
121121

122-
@media only screen and (max-width: 800px) {
122+
@media only screen and (max-width: 900px) {
123123
html, body {
124124
& > div {
125125
width: 85% !important;
126+
height: 50% !important;
127+
min-height: 300px !important;
126128

127129
& > div {
128130
flex-direction: column;

src/algo.ts

+41-11
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
import { Edge, Node, nullEdge } from './node';
1+
import { Edge, Node } from './node';
22
import { Graph } from './graph';
3-
import { Pair, PriorityQueue } from './queue';
3+
import { Pair, PriorityQueue, UnionFind } from './utils';
44

55
var TIMEOUT: number = 300;
66

@@ -24,8 +24,12 @@ async function _dfs (c: Node<number>, t: Node<number>, p: Array<Node<number>>) {
2424
for (const e of c.edges) {
2525
if (e.active) continue;
2626
const to: Node<number> = c.to(e);
27-
e.active = true;
27+
e.consider = true;
28+
to.consider = true;
2829
await sleep();
30+
e.consider = false;
31+
to.consider = false;
32+
e.active = true;
2933
await _dfs(to, t, p);
3034
if (p.slice(-1)[0] === t) {
3135
e.used = true;
@@ -49,7 +53,7 @@ export async function dfs (g: Graph<number>, ready: ()=>void) {
4953
export async function bfs (g: Graph<number>, ready: ()=>void) {
5054
const from: Node<number> = g.nodes[0];
5155
const to: Node<number> = g.nodes.slice(-1)[0];
52-
const q: Array<Pair<Node<number>, Edge<number>>> = [{ first: from, second: nullEdge() }];
56+
const q: Array<Pair<Node<number>, Edge<number>>> = [{ first: from, second: new Edge() }];
5357
let c: Pair<Node<number>, Edge<number>>;
5458
while (q.length > 0) {
5559
c = q.shift();
@@ -92,7 +96,7 @@ export async function dijkstra (g: Graph<number>, ready: ()=>void) {
9296
const to: Node<number> = g.nodes.slice(-1)[0];
9397
const q: PriorityQueue<number, Pair<Node<number>, Edge<number>>> = new PriorityQueue();
9498
var c: Pair<number, Pair<Node<number>, Edge<number>>>;
95-
q.push(0, { first: from, second: nullEdge() });
99+
q.push(0, { first: from, second: new Edge() });
96100
while (!q.empty()) {
97101
c = q.pop();
98102
if (c.second.second.from) {
@@ -134,7 +138,7 @@ export async function aStar (g: Graph<number>, ready: ()=>void) {
134138
const to: Node<number> = g.nodes.slice(-1)[0];
135139
const q: PriorityQueue<number, Pair<number, Pair<Node<number>, Edge<number>>>> = new PriorityQueue();
136140
var c: Pair<number, Pair<number, Pair<Node<number>, Edge<number>>>>;
137-
q.push(0, { first: 0, second: { first: from, second: nullEdge() } });
141+
q.push(0, { first: 0, second: { first: from, second: new Edge() } });
138142
while (!q.empty()) {
139143
c = q.pop();
140144
if (c.second.second.second.from) {
@@ -177,7 +181,7 @@ export async function aStar (g: Graph<number>, ready: ()=>void) {
177181
export async function prims (g: Graph<number>, ready: ()=>void) {
178182
const mst: Array<Edge<number>> = [];
179183
const q: PriorityQueue<number, Pair<Node<number>, Edge<number>>> = new PriorityQueue();
180-
q.push(0, { first: g.nodes[0], second: nullEdge() });
184+
q.push(0, { first: g.nodes[0], second: new Edge() });
181185
var c: Pair<number, Pair<Node<number>, Edge<number>>>;
182186
while (!q.empty()) {
183187
c = q.pop();
@@ -207,13 +211,39 @@ export async function prims (g: Graph<number>, ready: ()=>void) {
207211
e.to.used = true;
208212
e.used = true;
209213
}
210-
if (mst.length < g.nodes.length - 1) {
211-
g.reset();
212-
}
214+
if (mst.length < g.nodes.length - 1) g.reset();
213215
ready();
214216
};
215217

216-
export function kruskals (g: Graph<number>, ready: ()=>void): void {
218+
export async function kruskals (g: Graph<number>, ready: ()=>void) {
219+
const mst: Array<Edge<number>> = [];
220+
const edges: Array<Edge<number>> = [...new Set(g.nodes.map(n => n.edges).flat())];
221+
edges.sort((a: Edge<number>, b: Edge<number>) => a.cost - b.cost);
222+
const krusk: UnionFind<string> = new UnionFind(g.nodes.map(n => n.id));
223+
let c: Edge<number>;
224+
while (edges.length > 0) {
225+
c = edges.shift();
226+
c.consider = true;
227+
c.from.consider = true;
228+
c.to.consider = true;
229+
await sleep();
230+
c.consider = false;
231+
c.from.consider = false;
232+
c.to.consider = false;
233+
if (krusk.find(c.from.id) === krusk.find(c.to.id)) continue;
234+
krusk.union(c.from.id, c.to.id);
235+
c.active = true;
236+
c.from.active = true;
237+
c.to.active = true;
238+
mst.push(c);
239+
if (mst.length === g.nodes.length - 1) break;
240+
}
241+
for (const e of mst) {
242+
e.used = true;
243+
e.from.used = true;
244+
e.to.used = true;
245+
}
246+
if (mst.length < g.nodes.length - 1) g.reset();
217247
ready();
218248
};
219249

src/graph.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Node, Edge, nullEdge, genEdge } from './node';
1+
import { Node, Edge } from './node';
22
import { Canvas } from './canvas';
33

44
export class Graph<T> {
@@ -9,7 +9,7 @@ export class Graph<T> {
99
}
1010

1111
public addEdge (f: number, t: number, c: T): void {
12-
const e: Edge<T> = genEdge(this.nodes[f], this.nodes[t], c);
12+
const e: Edge<T> = new Edge(this.nodes[f], this.nodes[t], c);
1313
this.nodes[f].addEdge(e);
1414
this.nodes[t].addEdge(e);
1515
}
@@ -23,6 +23,7 @@ export class Graph<T> {
2323
n.edges.forEach(e => {
2424
e.active = false;
2525
e.used = false;
26+
e.consider = false;
2627
});
2728
});
2829
}

src/node.ts

+23-14
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,25 @@
11
import { Canvas } from './canvas';
22

3-
export interface Edge<T> {
4-
from: Node<T>;
5-
to: Node<T>;
6-
cost: T;
7-
active: boolean;
8-
used: boolean;
9-
consider: boolean;
10-
}
3+
export class Edge<T> {
4+
public from: Node<T>;
5+
public to: Node<T>;
6+
public cost: T;
7+
public active: boolean;
8+
public used: boolean;
9+
public consider: boolean;
1110

12-
export function genEdge<T> (from: Node<T>, to: Node<T>, cost: T): Edge<T> {
13-
return { from: from, to: to, cost: cost, active: false, used: false, consider: false };
14-
}
11+
constructor (from: Node<T> = null, to: Node<T> = null, cost: T = null) {
12+
this.from = from;
13+
this.to = to;
14+
this.cost = cost;
15+
this.active = false;
16+
this.used = false;
17+
this.consider = false;
18+
}
1519

16-
export function nullEdge<T> (): Edge<T> {
17-
return genEdge(null, null, null);
20+
public toString (): string {
21+
return this.from + ' -> ' + this.to;
22+
}
1823
}
1924

2025
const LETTERS: string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ';
@@ -43,8 +48,12 @@ export class Node<T> {
4348
this.l = l || LETTERS[Node.lind++];
4449
}
4550

51+
public get id (): string {
52+
return this.l;
53+
}
54+
4655
public addEdge (n: Node<T>|Edge<T>, c?: T): void {
47-
if (c && n instanceof Node) this.edges.push({ from: this, to: n, cost: c, active: false, used: false, consider: false });
56+
if (c && n instanceof Node) this.edges.push(new Edge(this, n, c));
4857
else this.edges.push(<Edge<T>> n);
4958
}
5059

src/queue.ts

-25
This file was deleted.

src/utils.ts

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
export interface Pair<T1, T2> {
2+
first: T1;
3+
second: T2;
4+
};
5+
6+
export class PriorityQueue<T1, T2> {
7+
private q: Array<Pair<T1, T2>> = [];
8+
9+
public push (p: T1, i: T2): void {
10+
this.q.push({ first: p, second: i });
11+
this.q.sort((a: Pair<T1, T2>, b: Pair<T1, T2>) => <any> a.first - <any> b.first);
12+
}
13+
14+
public pop (): Pair<T1, T2> {
15+
return this.q.pop();
16+
}
17+
18+
public empty (): boolean {
19+
return this.length === 0;
20+
}
21+
22+
public get length (): number {
23+
return this.q.length;
24+
}
25+
};
26+
27+
export class UnionFind<T> {
28+
private m: Map<T, T> = new Map();
29+
private s: Map<T, number> = new Map();
30+
31+
constructor (els: Array<T>) {
32+
for (const e of els) {
33+
this.m.set(e, e);
34+
this.s.set(e, 1);
35+
}
36+
}
37+
38+
public find (e: T): T {
39+
if (this.m.get(e) === e) return e;
40+
const root: T = this.find(this.m.get(e));
41+
this.m.set(e, root);
42+
return root;
43+
}
44+
45+
public union (a: T, b: T): void {
46+
if (this.s.get(a) < this.s.get(b)) [a, b] = [b, a];
47+
const root: T = this.find(a);
48+
this.m.set(b, root);
49+
this.s.set(root, this.s.get(root) + this.s.get(b));
50+
}
51+
};

tsconfig.json

+4
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,10 @@
55
"preserveConstEnums": true,
66
"outDir": "dist",
77
"target": "ES6",
8+
"lib": [
9+
"ES2019",
10+
"DOM"
11+
],
812
"moduleResolution": "node",
913
"sourceMap": true
1014
},

0 commit comments

Comments
 (0)