Skip to content

Commit 5da3ae8

Browse files
authored
Flood Fill in C (#741)
* Adding flood_fill.c * Updating flood_fill.md * adding C's queue_fill to flood_fill.md
1 parent b689488 commit 5da3ae8

File tree

2 files changed

+275
-1
lines changed

2 files changed

+275
-1
lines changed
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
#include <stdio.h>
2+
#include <stdlib.h>
3+
#include <string.h>
4+
5+
struct canvas {
6+
int max_x, max_y;
7+
int *data;
8+
};
9+
10+
struct point {
11+
int x, y;
12+
};
13+
14+
struct stack {
15+
size_t top, capacity;
16+
struct point *data;
17+
};
18+
19+
struct queue {
20+
size_t front, back, capacity;
21+
struct point *data;
22+
};
23+
24+
int inbounds(struct point p, struct canvas c) {
25+
return (p.x < 0 || p.y < 0 || p.y >= c.max_y || p.x >= c.max_x) ? 0 : 1;
26+
}
27+
28+
void color(struct canvas c, struct point p, int old_val, int new_val) {
29+
if (inbounds(p, c) && c.data[p.x + c.max_x * p.y] == old_val) {
30+
c.data[p.x + c.max_x * p.y] = new_val;
31+
}
32+
}
33+
34+
int find_neighbors(struct canvas c, struct point p, int old_val, int new_val,
35+
struct point *neighbors) {
36+
int cnt = 0;
37+
struct point points[4] = {
38+
{p.x, p.y + 1},
39+
{p.x + 1, p.y},
40+
{p.x, p.y - 1},
41+
{p.x - 1, p.y}
42+
};
43+
44+
for (int i = 0; i < 4; ++i) {
45+
if (inbounds(points[i], c) &&
46+
c.data[points[i].x + c.max_x * points[i].y] == old_val) {
47+
neighbors[cnt++] = points[i];
48+
}
49+
}
50+
51+
return cnt;
52+
}
53+
54+
struct stack get_stack() {
55+
struct stack stk;
56+
57+
stk.data = malloc(4 * sizeof(struct point));
58+
stk.capacity = 4;
59+
stk.top = 0;
60+
61+
return stk;
62+
}
63+
64+
int stack_empty(struct stack stk) {
65+
return stk.top == 0;
66+
}
67+
68+
void stack_push(struct stack *stk, struct point element) {
69+
if (stk->top == stk->capacity) {
70+
stk->capacity *= 2;
71+
stk->data = realloc(stk->data, stk->capacity * sizeof(stk->data[0]));
72+
}
73+
74+
stk->data[stk->top++] = element;
75+
}
76+
77+
struct point stack_pop(struct stack *stk) {
78+
return stk->data[--stk->top];
79+
}
80+
81+
void free_stack(struct stack stk) {
82+
free(stk.data);
83+
}
84+
85+
void stack_fill(struct canvas c, struct point p, int old_val, int new_val) {
86+
if (old_val == new_val) {
87+
return;
88+
}
89+
90+
struct stack stk = get_stack();
91+
stack_push(&stk, p);
92+
93+
while (!stack_empty(stk)) {
94+
struct point cur_loc = stack_pop(&stk);
95+
if (c.data[cur_loc.x + c.max_x * cur_loc.y] == old_val) {
96+
color(c, cur_loc, old_val, new_val);
97+
98+
struct point neighbors[4];
99+
int cnt = find_neighbors(c, cur_loc, old_val, new_val, neighbors);
100+
101+
for (int i = 0; i < cnt; ++i) {
102+
stack_push(&stk, neighbors[i]);
103+
}
104+
}
105+
}
106+
107+
free_stack(stk);
108+
}
109+
110+
struct queue get_queue() {
111+
struct queue q;
112+
113+
q.data = calloc(4, sizeof(struct point));
114+
q.front = 0;
115+
q.back = 0;
116+
q.capacity = 4;
117+
118+
return q;
119+
}
120+
121+
int queue_empty(struct queue q) {
122+
return q.front == q.back;
123+
}
124+
125+
void enqueue(struct queue *q, struct point element) {
126+
if (q->front == (q->back + 1) % q->capacity) {
127+
size_t size = sizeof(q->data[0]);
128+
struct point *tmp = calloc((q->capacity * 2), size);
129+
memcpy(tmp, q->data + q->front, (q->capacity - q->front) * size);
130+
memcpy(tmp + q->capacity - q->front, q->data, (q->front - 1) * size);
131+
132+
free(q->data);
133+
134+
q->data = tmp;
135+
q->back = q->capacity - 1;
136+
q->front = 0;
137+
q->capacity *= 2;
138+
}
139+
140+
q->data[q->back] = element;
141+
q->back = (q->back + 1) % q->capacity;
142+
}
143+
144+
struct point dequeue(struct queue *q) {
145+
struct point ret = q->data[q->front];
146+
q->front = (q->front + 1) % q->capacity;
147+
148+
return ret;
149+
}
150+
151+
void free_queue(struct queue q) {
152+
free(q.data);
153+
}
154+
155+
void queue_fill(struct canvas c, struct point p, int old_val, int new_val) {
156+
if (old_val == new_val) {
157+
return;
158+
}
159+
160+
struct queue q = get_queue(sizeof(struct point *));
161+
enqueue(&q, p);
162+
163+
while (!queue_empty(q)) {
164+
struct point cur_loc = dequeue(&q);
165+
if (c.data[cur_loc.x + c.max_x * cur_loc.y] == old_val) {
166+
color(c, cur_loc, old_val, new_val);
167+
168+
struct point neighbors[4];
169+
int cnt = find_neighbors(c, cur_loc, old_val, new_val, neighbors);
170+
171+
for (int i = 0; i < cnt; ++i) {
172+
enqueue(&q, neighbors[i]);
173+
}
174+
}
175+
}
176+
177+
free_queue(q);
178+
}
179+
180+
void recursive_fill(struct canvas c, struct point p, int old_val,
181+
int new_val) {
182+
183+
if (old_val == new_val) {
184+
return;
185+
}
186+
187+
color(c, p, old_val, new_val);
188+
189+
struct point neighbors[4];
190+
int cnt = find_neighbors(c, p, old_val, new_val, neighbors);
191+
192+
for (int i = 0; i < cnt; ++i) {
193+
recursive_fill(c, neighbors[i], old_val, new_val);
194+
}
195+
}
196+
197+
int grid_cmp(int *a, int *b, int size) {
198+
for (int i = 0; i < size; ++i) {
199+
if (a[i] != b[i]) {
200+
return 0;
201+
}
202+
}
203+
204+
return 1;
205+
}
206+
207+
int main() {
208+
int grid[25] = {
209+
0, 0, 0, 0, 0,
210+
0, 0, 0, 0, 0,
211+
1, 1, 1, 1, 1,
212+
0, 0, 0, 0, 0,
213+
0, 0, 0, 0, 0
214+
};
215+
int grid1[25] = {
216+
0, 0, 0, 0, 0,
217+
0, 0, 0, 0, 0,
218+
1, 1, 1, 1, 1,
219+
0, 0, 0, 0, 0,
220+
0, 0, 0, 0, 0
221+
};
222+
int grid2[25] = {
223+
0, 0, 0, 0, 0,
224+
0, 0, 0, 0, 0,
225+
1, 1, 1, 1, 1,
226+
0, 0, 0, 0, 0,
227+
0, 0, 0, 0, 0
228+
};
229+
int answer_grid[25] = {
230+
1, 1, 1, 1, 1,
231+
1, 1, 1, 1, 1,
232+
1, 1, 1, 1, 1,
233+
0, 0, 0, 0, 0,
234+
0, 0, 0, 0, 0
235+
};
236+
237+
struct canvas c = {5, 5, grid};
238+
struct canvas c1 = {5, 5, grid1};
239+
struct canvas c2 = {5, 5, grid2};
240+
241+
struct point start_loc = {0, 0};
242+
243+
int pass_cnt = 0;
244+
245+
recursive_fill(c, start_loc, 0, 1);
246+
pass_cnt += grid_cmp(grid, answer_grid, 25);
247+
248+
stack_fill(c1, start_loc, 0, 1);
249+
pass_cnt += grid_cmp(grid1, answer_grid, 25);
250+
251+
queue_fill(c2, start_loc, 0, 1);
252+
pass_cnt += grid_cmp(grid2, answer_grid, 25);
253+
254+
printf("Test Summary: | Pass\tTotal\n");
255+
printf("Fill Methods |\t%d\t3\n", pass_cnt);
256+
257+
return 0;
258+
}
259+

contents/flood_fill/flood_fill.md

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,8 @@ In code, this might look like this:
8888
{% method %}
8989
{% sample lang="jl" %}
9090
[import:37-55, lang:"julia"](code/julia/flood_fill.jl)
91+
{% sample lang="c" %}
92+
[import:34-52, lang:"c"](code/c/flood_fill.c)
9193
{% endmethod %}
9294

9395

@@ -102,10 +104,17 @@ In code, it might look like this:
102104
{% method %}
103105
{% sample lang="jl" %}
104106
[import:106-118, lang:"julia"](code/julia/flood_fill.jl)
107+
{% sample lang="c" %}
108+
[import:180-195, lang:"c"](code/c/flood_fill.c)
109+
{% endmethod %}
105110

106-
All Julia code snippets for this chapter rely on an exterior `color!(...)` function, defined as
111+
All code snippets for this chapter rely on an exterior `color` function, defined as
107112

113+
{% method %}
114+
{% sample lang="jl" %}
108115
[import:23-35, lang:"julia"](code/julia/flood_fill.jl)
116+
{% sample lang="c" %}
117+
[import:28-32, lang:"c"](code/c/flood_fill.c)
109118
{% endmethod %}
110119

111120
The above code continues recursing through available neighbors as long as neighbors exist, and this should work so long as we are adding the correct set of neighbors.
@@ -115,6 +124,8 @@ Additionally, it is possible to do the same type of traversal by managing a stac
115124
{% method %}
116125
{% sample lang="jl" %}
117126
[import:57-77, lang:"julia"](code/julia/flood_fill.jl)
127+
{% sample lang="c" %}
128+
[import:85-108, lang:"c"](code/c/flood_fill.c)
118129
{% endmethod %}
119130

120131
This is ultimately the same method of traversal as before; however, because we are managing our own data structure, there are a few distinct differences:
@@ -152,6 +163,8 @@ The code would look something like this:
152163
{% method %}
153164
{% sample lang="jl" %}
154165
[import:80-104, lang:"julia"](code/julia/flood_fill.jl)
166+
{% sample lang="c" %}
167+
[import:155-178, lang:"c"](code/c/flood_fill.c)
155168
{% endmethod %}
156169

157170
Now, there is a small trick in this code that must be considered to make sure it runs optimally.
@@ -228,6 +241,8 @@ After, we will fill in the left-hand side of the array to be all ones by choosin
228241
{% method %}
229242
{% sample lang="jl" %}
230243
[import, lang:"julia"](code/julia/flood_fill.jl)
244+
{% sample lang="c" %}
245+
[import, lang:"c"](code/c/flood_fill.c)
231246
{% endmethod %}
232247

233248

0 commit comments

Comments
 (0)