Compare commits

...

25 Commits

Author SHA1 Message Date
9e270b7425 后续考虑matrix是利用list来实现还是直接函数指针实现。但考虑到用一维指针或者二维指针都有不方便的地方。 2025-04-27 00:16:44 +08:00
5fd74a4d15 dfs和bfs代码优化完毕,现在思路非常清晰了 2025-04-26 19:00:20 +08:00
9d5f71250e graph封装底层,让dfs和dfs代码看起来更加直观 2025-04-26 18:43:59 +08:00
5a2c2ceccc graph->DFS调试通过 2025-04-26 18:22:47 +08:00
5e83dc2917 思路楼乱了 2025-04-26 17:27:05 +08:00
43b237487a 无边的节点没有被压到栈中去 2025-04-26 16:02:16 +08:00
43706105bb graph的迭代器bfs遍历模式调试通过 2025-04-26 15:12:43 +08:00
98eb005a4a bfs的遍历还存在问题 2025-04-26 15:01:15 +08:00
ce973043d8 graph默认只对顶点进行遍历,后续实现bfs和dfs 2025-04-26 13:40:23 +08:00
3ac92de18e 边的核心操作都添测试通过了,但是我个人觉得写的不好。后续再考虑优化。 2025-04-25 18:19:22 +08:00
c411ee96eb add_edge调试通过,后续再区分是有向图还是无向图 2025-04-25 16:56:58 +08:00
f63aa4db0a 为什么from_node和to_node的obj不符合预期 2025-04-25 16:55:22 +08:00
7ad5631aec 目前edge打印还是有错误,from和to的顶点不对 2025-04-25 16:32:11 +08:00
c3ed2ab00d edge添加边代码修改 2025-04-25 16:11:40 +08:00
628df4c1a0 添加add_edge单元测试 2025-04-25 16:04:14 +08:00
49bc8b0cc4 添加add_edge的代码 2025-04-25 15:53:50 +08:00
6965fa1e25 添加edge的新建和释放函数 2025-04-25 14:07:37 +08:00
0520bb99ae 顶点链表方式调试通过 2025-04-25 14:04:14 +08:00
238c16c3ec graph删除顶点和查找顶点的接口都测试通过 2025-04-25 13:56:32 +08:00
163f3c55da vertex的添加代码实现并调试通过 2025-04-25 13:39:17 +08:00
46f1f365fb 添加新增的graph成员函数定义 2025-04-25 13:16:16 +08:00
af1a3703ba graph的vertex和edge结构体都重新定义,kernel函数也重新命名 2025-04-25 13:03:23 +08:00
b788dd74ee graph结构体node重新规划 2025-04-25 10:47:42 +08:00
c661ebaea6 【性能比较】添加常用数据结构时间复杂度和空间复杂度小结表 2025-04-25 10:29:49 +08:00
4fb9ed9d58 graph修改代码结构 2025-04-25 10:04:03 +08:00
4 changed files with 1161 additions and 150 deletions

View File

@ -36,14 +36,23 @@
## 性能比较 ## 性能比较
|项目| 数组| 链表| | 数据结构 | < | 时 |间 | | 复 | 杂 |度 | > | <空间复杂度> |
|---|---|---| |---|---|---|---|---|---|---|---|---|---|
|查找| $O(1)$ | $O(n)$ | |---|(|**平**|**均**|) | (|**最**|**坏**| ) |**最坏**|
|插入| $O(n)$ | $O(1)$ | |---|访问|搜索|插入|删除|访问|搜索|插入|删除|---|
|删除| $O(n)$ | $O(1)$ | | 数组 | $O(1)$ | $O(n)$ | $O(n)$ | $O(n)$ | $O(1)$ | $O(n)$ | $O(n)$ | $O(n)$ | $O(n)$ |
| 栈 | $O(n)$ | $O(n)$ | $O(1)$ | $O(1)$ | $O(n)$ | $O(n)$ | $O(1)$ | $O(1)$ | $O(n)$ |
**【A1】** 若链表的操作流程为,先查找元素再删除元素。那么时间复杂度确实是$O(n)$。但是链表的增删优势,在其他应用有体现。比如双向队列,插入和删除效率都为$O(1)$。 | 队列 | $O(n)$ | $O(n)$ | $O(1)$ | $O(1)$ | $O(n)$ | $O(n)$ | $O(1)$ | $O(1)$ | $O(n)$ |
| 单向链表 | $O(n)$ | $O(n)$ | $O(1)$ | $O(1)$ | $O(n)$ | $O(n)$ | $O(1)$ | $O(1)$ | $O(n)$ |
| 双向链表 | $O(n)$ | $O(n)$ | $O(1)$ | $O(1)$ | $O(n)$ | $O(n)$ | $O(1)$ | $O(1)$ | $O(n)$ |
| 跳表 | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(n)$ | $O(n)$ | $O(n)$ | $O(n)$ | $O(n*log(n))$ |
| 哈希表 | $N/A$ | $O(1)$ | $O(1)$ | $O(1)$ | $N/A$ | $O(n)$ | $O(n)$ | $O(n)$ | $O(n)$
| 二叉搜索树 | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(n)$ | $O(n)$ | $O(n)$ | $O(n)$ | $O(n)$ |
| AVL树 | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(n)$ |
| 红黑树 | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(n)$ |
| B树 | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(log(n))$ | $O(n)$ |
**【答疑】** 若链表的操作流程为,先查找元素再删除元素。那么时间复杂度确实是$O(n)$。但是链表的增删优势,在其他应用有体现。比如双向队列,插入和删除效率都为$O(1)$。
## 规范 ## 规范
### 版本说明 ### 版本说明

View File

@ -13,50 +13,97 @@
#include "common.h" #include "common.h"
struct _graph_node { #include "stack.h"
void *obj; #include "queue.h"
uint32_t **edge;
uint8_t *visited; enum _graph_type
{
GRAPH_UNDIRECTED,
GRAPH_DIRECTED,
// GRAPH_UNDIRECTED_WEIGHT,
// GRAPH_DIRECTED_WEIGHT,
}; };
struct _graph { enum _graph_search
{
GRAPH_DFS,
GRAPH_BFS,
};
struct _graph_edge
{
uint32_t weight;
struct _graph_edge* next;
void *target;
};
struct _graph_node
{
void* obj;
struct _graph_node* next;
bool visited;
struct _graph_edge* edgehead;
};
struct _graph
{
// -------------------- private --------------------
struct _graph_node* _head; struct _graph_node* _head;
uint32_t **edges;
uint32_t _size; uint32_t _size;
uint32_t _obj_size; uint32_t _obj_size;
uint32_t _capacity; uint32_t _capacity;
uint32_t _ratio; uint32_t _ratio;
// init enum _graph_type _type;
void (*init)(struct _graph *self); enum _graph_search _search;
bool (*from_matrix)(struct _graph *self, void *obj, uint32_t *edges, uint32_t size);
stack_t stack;
queue_t queue;
struct _iterator _iter;
void (*_destory)(struct _graph* self);
// -------------------- public --------------------
// kernel // kernel
bool (*add)(struct _graph *self, void *obj); // -> vertex
bool (*get)(struct _graph *self, uint32_t idx, void *obj); bool (*add_vertex)(struct _graph* self, void* obj);
bool (*remove)(struct _graph *self, uint32_t idx); bool (*del_vertex)(struct _graph* self, void* obj);
bool (*find_vertex)(struct _graph* self, void* obj);
// base // -> edge
uint32_t (*size)(struct _graph *self); bool (*add_edge)(struct _graph* self, void* from, void* to, uint32_t weight);
uint32_t (*capacity)(struct _graph *self); bool (*del_edge)(struct _graph* self, void* from, void* to);
bool (*find_edge)(struct _graph* self, void* from, void* to);
bool (*empty)(struct _graph* self); bool (*empty)(struct _graph* self);
bool (*full)(struct _graph* self); bool (*full)(struct _graph* self);
bool (*dfs)(struct _graph *self, uint32_t idx); // base
bool (*bfs)(struct _graph *self, uint32_t idx); uint32_t(*size)(struct _graph* self);
uint32_t(*capacity)(struct _graph* self);
//
bool (*clear)(struct _graph* self); bool (*clear)(struct _graph* self);
void (*destory)(struct _graph *self);
// iter
iterator_t (*iter)(struct _graph* self, enum _graph_search search, void *obj);
// config
compare_fun_t compare; // !!! you have to implement this function
// others
bool (*from_matrix)(struct _graph* self, void* obj, uint32_t* edges, uint32_t size);
// -------------------- debug --------------------
void (*print)(struct _graph* self); void (*print)(struct _graph* self);
void (*print_obj)(void* obj); void (*print_obj)(void* obj);
}; };
typedef struct _graph* graph_t; typedef struct _graph* graph_t;
graph_t graph_new2(uint32_t obj_size, uint32_t capacity); graph_t graph_new(uint32_t obj_size);
// graph_t graph_new2(uint32_t obj_size, uint32_t capacity);
void graph_free(graph_t* graph); void graph_free(graph_t* graph);
#endif #endif

View File

@ -12,6 +12,7 @@
#include "queue.h" #include "queue.h"
#include "stack.h" #include "stack.h"
#if 0
static uint32_t graph_size(struct _graph* self) static uint32_t graph_size(struct _graph* self)
{ {
if (self == NULL) if (self == NULL)
@ -188,12 +189,70 @@ static bool graph_dfs(struct _graph *self, uint32_t idx)
} }
static void graph_init2(struct _graph *self) static bool graph_init2(struct _graph* self, uint32_t obj_size, uint32_t capacity)
{ {
if(self == NULL || self->_head == NULL) assert(self != NULL);
if (self == NULL)
{ {
return; return false;
} }
uint32_t edges = 0;
// -------------------- private --------------------
self->_size = 0;
self->_obj_size = obj_size;
self->_capacity = capacity;
self->_ratio = 1;
self->_head = (struct _graph_node*)malloc(sizeof(struct _graph_node));
if (self->_head == NULL)
{
goto done;
}
self->_head->obj = (void*)malloc(self->_obj_size);
if (self->_head->obj == NULL)
{
goto done1;
}
self->_head->edge = (uint32_t**)malloc(self->_capacity * sizeof(uint32_t*));
if (self->_head->edge == NULL)
{
goto done2;
}
uint32_t i = 0;
for (i = 0; i < self->_capacity; i++)
{
self->_head->edge[i] = (uint32_t*)malloc(self->_capacity * sizeof(uint32_t));
if (self->_head->edge[i] == NULL)
{
edges += 1;
goto done3;
}
}
self->_head->visited = (uint8_t*)calloc(1, self->_capacity * sizeof(uint8_t));
if (self->_head->visited == NULL)
{
goto done4;
}
self->_destory = graph_destory;
// -------------------- public --------------------
self->size = graph_size;
self->capacity = graph_capacity;
self->clear = graph_clear;
self->from_matrix = graph_from_matrix;
self->bfs = graph_bfs;
self->dfs = graph_dfs;
// -------------------- debug --------------------
self->print_obj = NULL;
self->print = graph_print;
for (uint32_t i = 0; i < self->_capacity; i++) for (uint32_t i = 0; i < self->_capacity; i++)
{ {
@ -203,96 +262,40 @@ static void graph_init2(struct _graph *self)
self->_head->edge[i][j] = 0; self->_head->edge[i][j] = 0;
} }
} }
return true;
done4:
done3:
for (uint32_t j = 0; j < edges; j++)
{
free(self->_head->edge[j]);
}
free(self->_head->edge);
done2:
free(self->_head->obj);
done1:
free(self->_head);
done:
return false;
} }
graph_t graph_new2(uint32_t obj_size, uint32_t capacity) graph_t graph_new2(uint32_t obj_size, uint32_t capacity)
{ {
if(obj_size == 0 || capacity == 0) graph_t graph = NULL;
{ graph = malloc(sizeof(struct _graph));
return NULL;
}
graph_t graph = malloc(sizeof(struct _graph));
if (graph == NULL) if (graph == NULL)
{ {
goto done;
}
graph->_size = 0;
graph->_obj_size = obj_size;
graph->_capacity = capacity;
graph->_ratio = 1;
graph->init = graph_init2;
graph->destory = graph_destory;
graph->size = graph_size;
graph->capacity = graph_capacity;
graph->clear = graph_clear;
graph->from_matrix = graph_from_matrix;
graph->bfs = graph_bfs;
graph->dfs = graph_dfs;
graph->print_obj = NULL;
graph->print = graph_print;
graph->_head = (struct _graph_node *)malloc(sizeof(struct _graph_node));
if(graph->_head == NULL)
{
goto done1;
}
graph->_head->obj = (void *)malloc(graph->_obj_size);
if(graph->_head->obj == NULL)
{
goto done2;
}
graph->_head->edge = (uint32_t **)malloc(graph->_capacity * sizeof(uint32_t *));
if(graph->_head->edge == NULL)
{
goto done3;
}
uint32_t i = 0;
for(i = 0; i < graph->_capacity; i++)
{
graph->_head->edge[i] = (uint32_t *)malloc(graph->_capacity * sizeof(uint32_t));
if(graph->_head->edge[i] == NULL)
{
goto done4;
}
}
graph->_head->visited = (uint8_t *)calloc(1, graph->_capacity * sizeof(uint8_t));
if(graph->_head->visited == NULL)
{
goto done5;
}
// init graph
graph->init(graph);
return graph;
done5:
done4:
for(uint32_t j = 0; j < i; j++)
{
free(graph->_head->edge[j]);
}
free(graph->_head->edge);
done3:
free(graph->_head->obj);
done2:
free(graph->_head);
done1:
free(graph);
done:
return NULL; return NULL;
} }
// if(graph_init2(graph, obj_size, capacity) != true)
// {
// free(graph);
// return NULL;
// }
return graph;
}
void graph_free(graph_t* graph) void graph_free(graph_t* graph)
{ {
if (graph == NULL || *graph == NULL) if (graph == NULL || *graph == NULL)
@ -300,7 +303,795 @@ void graph_free(graph_t *graph)
return; return;
} }
(*graph)->destory(*graph); (*graph)->_destory(*graph);
free(*graph);
*graph = NULL;
}
#endif
static struct _graph_node *graph_node_new(void *obj, uint32_t obj_size)
{
void *new_obj = (void *)calloc(1, obj_size);
if (new_obj == NULL)
{
return NULL;
}
memmove(new_obj, obj, obj_size);
struct _graph_node *new_node = (struct _graph_node *)malloc(sizeof(struct _graph_node));
if (new_node == NULL)
{
free(new_obj);
return NULL;
}
new_node->obj = new_obj;
new_node->next = NULL;
new_node->edgehead = NULL;
new_node->visited = false;
return new_node;
}
static void greph_node_free(struct _graph_node **node)
{
if (node != NULL && *node != NULL)
{
if ((*node)->obj != NULL)
{
free((*node)->obj);
(*node)->obj = NULL;
}
if ((*node)->edgehead != NULL)
{
free((*node)->edgehead);
(*node)->edgehead = NULL;
}
free(*node);
*node = NULL;
}
}
static struct _graph_edge *graph_edge_new(void *target, uint32_t weight)
{
struct _graph_edge *new_edge = (struct _graph_edge *)malloc(sizeof(struct _graph_edge));
if (new_edge == NULL)
{
return NULL;
}
new_edge->next = NULL;
new_edge->weight = weight;
new_edge->target = target;
return new_edge;
}
static void graph_edge_free(struct _graph_edge **edge)
{
if (edge != NULL && *edge != NULL)
{
free(*edge);
*edge = NULL;
}
}
static uint32_t graph_size(struct _graph *self)
{
if (self == NULL)
{
return 0;
}
return self->_size;
}
static bool graph_empty(struct _graph *self)
{
if (self == NULL)
{
return 0;
}
return self->size(self) == 0;
}
static uint32_t graph_capacity(struct _graph *self)
{
if (self == NULL)
{
return 0;
}
return self->_capacity;
}
static bool graph_clear(struct _graph *self)
{
if (self == NULL && self->_head == NULL)
{
return 0;
}
struct _graph_node *cur = self->_head->next;
struct _graph_node *next = NULL;
while (cur != NULL)
{
next = cur->next;
greph_node_free(&cur);
cur = next;
}
self->_head->next = NULL;
self->_size = 0;
return true;
}
static void graph_destory(struct _graph *self)
{
if (self == NULL)
{
return;
}
self->clear(self);
if (self->_head != NULL)
{
free(self->_head);
self->_head = NULL;
}
if (self->stack != NULL)
{
stack_free(&self->stack);
}
if (self->queue != NULL)
{
queue_free(&self->queue);
}
}
static void graph_print(struct _graph *self)
{
if (self == NULL || self->_head == NULL || self->print_obj == NULL)
{
return;
}
printf("\nvertex : \n");
struct _graph_node *cur = self->_head->next;
while (cur != NULL)
{
self->print_obj(cur->obj);
cur = cur->next;
}
printf("\n");
printf("edge : \n");
cur = self->_head->next;
while (cur != NULL)
{
if (cur->edgehead != NULL)
{
struct _graph_edge *edge = cur->edgehead;
while (edge != NULL)
{
struct _graph_node *target = (struct _graph_node *)edge->target;
// printf("from ");
self->print_obj(cur->obj);
// printf(" to ");
printf("--> ");
self->print_obj(target->obj);
printf(": %d \n", edge->weight);
edge = edge->next;
}
}
cur = cur->next;
}
printf("\n");
printf("print done.\n");
}
static bool graph_add_vertex(struct _graph *self, void *obj)
{
assert(self != NULL);
if (self->_head->next == NULL)
{
// no vertex
struct _graph_node *new_node = graph_node_new(obj, self->_obj_size);
if (new_node == NULL)
{
return false;
}
self->_head->next = new_node;
}
else
{
struct _graph_node *cur = self->_head->next;
// find if exist
while (cur != NULL)
{
if (self->compare(cur->obj, obj) == 0)
{
return true;
}
cur = cur->next;
}
struct _graph_node *new_node = graph_node_new(obj, self->_obj_size);
if (new_node == NULL)
{
return false;
}
// add to tail
cur = self->_head->next;
while (cur->next != NULL)
{
cur = cur->next;
}
cur->next = new_node;
}
self->_size++;
return true;
}
static bool graph_del_vertex(struct _graph *self, void *obj)
{
assert(self != NULL);
if (obj == NULL)
{
return false;
}
if (self->empty(self))
{
return false;
}
struct _graph_node *cur = self->_head->next;
struct _graph_node *pre = self->_head;
while (cur != NULL)
{
if (self->compare(cur->obj, obj) == 0)
{
pre->next = cur->next;
break;
}
pre = cur;
cur = cur->next;
}
if (cur == NULL)
{
return false;
}
greph_node_free(&cur);
self->_size--;
return true;
}
static bool graph_find_vertex(struct _graph *self, void *obj)
{
assert(self != NULL);
if (obj == NULL)
{
return false;
}
if (self->empty(self))
{
return false;
}
struct _graph_node *cur = self->_head->next;
while (cur != NULL)
{
if (self->compare(cur->obj, obj) == 0)
{
// obj is found
break;
}
cur = cur->next;
}
return cur == NULL ? false : true;
}
static struct _graph_node *find_node(struct _graph *self, void *obj)
{
struct _graph_node *cur = self->_head->next;
while (cur != NULL)
{
if (self->compare(cur->obj, obj) == 0)
{
// obj is found
break;
}
cur = cur->next;
}
return cur;
}
static bool graph_add_edge(struct _graph *self, void *from, void *to, uint32_t weight)
{
assert(self != NULL);
if (self->empty(self))
{
return false;
}
struct _graph_node *from_node = self->_head->next;
struct _graph_node *to_node = self->_head->next;
from_node = find_node(self, from);
if (from_node == NULL)
{
return false;
}
to_node = find_node(self, to);
if (to_node == NULL)
{
return false;
}
// from_node add edge
struct _graph_edge *new_edge = graph_edge_new(to_node, weight);
if (new_edge == NULL)
{
return false;
}
if (from_node->edgehead == NULL)
{
from_node->edgehead = new_edge;
}
else
{
new_edge->next = from_node->edgehead->next;
from_node->edgehead->next = new_edge;
}
if (self->_type == GRAPH_UNDIRECTED)
{
// if graph is undirected
// to_node add edge
struct _graph_edge *new_edge2 = graph_edge_new(from_node, weight);
if (new_edge2 == NULL)
{
return false;
}
if (to_node->edgehead == NULL)
{
to_node->edgehead = new_edge2;
}
else
{
new_edge2->next = to_node->edgehead->next;
to_node->edgehead->next = new_edge2;
}
}
return true;
}
static bool graph_del_edge(struct _graph *self, void *from, void *to)
{
assert(self != NULL);
if (self->empty(self))
{
return false;
}
struct _graph_node *from_node = self->_head->next;
struct _graph_node *to_node = self->_head->next;
from_node = find_node(self, from);
if (from_node == NULL)
{
return false;
}
to_node = find_node(self, to);
if (to_node == NULL)
{
return false;
}
struct _graph_edge *cur = from_node->edgehead;
struct _graph_edge *pre = from_node->edgehead;
while (cur != NULL)
{
if (cur->target == to_node)
{
pre->next = cur->next;
if (pre == cur)
{
from_node->edgehead = cur->next;
}
graph_edge_free(&cur);
break;
}
pre = cur;
cur = cur->next;
}
if (self->_type == GRAPH_UNDIRECTED)
{
struct _graph_edge *cur2 = to_node->edgehead;
struct _graph_edge *pre2 = to_node->edgehead;
while (cur2 != NULL)
{
if (cur2->target == from_node)
{
pre2->next = cur2->next;
if (pre2 == cur2)
{
to_node->edgehead = cur2->next;
}
graph_edge_free(&cur2);
break;
}
pre2 = cur2;
cur2 = cur2->next;
}
}
return true;
}
static bool graph_find_edge(struct _graph *self, void *from, void *to)
{
assert(self != NULL);
if (self->empty(self))
{
return false;
}
struct _graph_node *from_node = self->_head->next;
struct _graph_node *to_node = self->_head->next;
from_node = find_node(self, from);
if (from_node == NULL)
{
return false;
}
to_node = find_node(self, to);
if (to_node == NULL)
{
return false;
}
struct _graph_edge *cur = from_node->edgehead;
while (cur != NULL)
{
if (cur->target == to_node)
{
// found edge
break;
}
cur = cur->next;
}
if (cur == NULL)
{
return false;
}
return true;
}
static struct _graph_node * graph_find_unvisited_vertex(struct _graph *self)
{
assert(self != NULL);
if (self->empty(self))
{
return false;
}
struct _graph_node *node = self->_head->next;
while(node != NULL)
{
if(node->visited == false)
{
return node;
}
node = node->next;
}
return NULL;
}
static struct _graph_node * graph_find_next_unvisited_target(struct _graph *self, struct _graph_node *node)
{
assert(self != NULL);
if (self->empty(self))
{
return NULL;
}
if(node == NULL)
{
return NULL;
}
struct _graph_edge *edge = node->edgehead;
struct _graph_node *target = NULL;
while(edge != NULL)
{
target = edge->target;
if(target != NULL && target->visited != true)
{
return target;
}
edge = edge->next;
}
return NULL;
}
iterator_t graph_iter(struct _graph *self, enum _graph_search search_type, void *start)
{
assert(self != NULL);
iterator_t iter = &self->_iter;
iter->_parent = self;
iter->_cur = 0;
iter->_cur_node = self->_head->next;
struct _graph_node *start_node = find_node(self, start);
if (start_node == NULL)
{
goto done;
}
iter->_cur_node = start_node;
struct _graph_node *node = self->_head->next;
while (node != NULL)
{
node->visited = false;
node = node->next;
}
self->_search = search_type;
switch (self->_search)
{
case GRAPH_BFS:
{
self->queue->push(self->queue, &iter->_cur_node);
}
break;
case GRAPH_DFS:
{
// pass
}
break;
default:
{
}
break;
}
done:
return iter;
}
bool graph_iter_hasnext(struct _iterator *iter)
{
assert(iter != NULL);
assert(iter->parent != NULL);
graph_t self = (graph_t)iter->_parent;
if (iter->_cur < self->size(self))
{
return true;
}
return false;
}
const void *graph_iter_next(struct _iterator *iter)
{
assert(iter != NULL);
assert(iter->parent != NULL);
graph_t self = (graph_t)iter->_parent;
void *obj = NULL;
iter->_cur += 1;
switch (self->_search)
{
case GRAPH_BFS:
{
struct _graph_node *cur_node = iter->_cur_node;
struct _graph_edge *cur_edge = cur_node->edgehead;
struct _graph_node *target = NULL;
struct _graph_node *node = cur_node;
queue_t queue = self->queue;
// 3. [graph special] if queue is empty, find a new root node
if (queue->empty(queue))
{
cur_node = graph_find_unvisited_vertex(self);
if(cur_node != NULL)
{
queue->push(queue, &cur_node);
}
}
// graph->BFS : similar to breadth-first traversal of a tree
if (!queue->empty(queue) && node != NULL)
{
// 1. pop the root vertex from queue
queue->pop(queue, &node);
node->visited = true;
// 2. find all unvisited target node and push them to queue
cur_edge = node->edgehead;
while (cur_edge != NULL)
{
target = cur_edge->target;
if (target != NULL && target->visited != true)
{
queue->push(queue, &target);
}
cur_edge = cur_edge->next;
}
cur_node = node;
}
iter->_cur_node = cur_node;
obj = cur_node->obj;
}
break;
case GRAPH_DFS:
{
// self->stack->push(self->stack, iter->_cur_node);
struct _graph_node *cur_node = self->_iter._cur_node;
struct _graph_node *node = NULL;
stack_t stack = self->stack;
// graph->DFS : similar to the preorder traversal of a tree
while (!self->stack->empty(self->stack) || cur_node != NULL)
{
if (cur_node != NULL)
{
// 1. get current node
node = cur_node;
// 2. push current node to stack
self->stack->push(self->stack, &cur_node);
cur_node->visited = true;
// 3. find unvisited target node
cur_node = graph_find_next_unvisited_target(self, cur_node);
break;
}
else
{
// 4. if cur_node is NULL, pop from stack and find unvisited target node
self->stack->pop(self->stack, &cur_node);
// 5. find unvisited target node
cur_node = graph_find_next_unvisited_target(self, cur_node);
// 6. [graph special] If the graph contains isolated vertices
if(cur_node == NULL)
{
cur_node = graph_find_unvisited_vertex(self);
}
}
}
iter->_cur_node = cur_node;
obj = node->obj;
}
break;
default:
{
}
break;
}
return obj;
}
static bool graph_init(struct _graph *self, uint32_t obj_size)
{
assert(self != NULL);
if (self == NULL)
{
return false;
}
// -------------------- private --------------------
self->_size = 0;
self->_obj_size = obj_size;
self->_capacity = UINT32_MAX;
self->_ratio = 1;
self->stack = stack_new(sizeof(struct _graph_node *));
if (self->stack == NULL)
{
return false;
}
self->queue = queue_new(sizeof(struct _graph_node *));
if (self->queue == NULL)
{
stack_free(&self->stack);
return false;
}
self->_head = (struct _graph_node *)malloc(sizeof(struct _graph_node));
if (self->_head == NULL)
{
stack_free(&self->stack);
queue_free(&self->queue);
return false;
}
self->_head->visited = false;
self->_head->obj = NULL;
self->_head->edgehead = NULL;
self->_head->next = NULL;
self->_type = GRAPH_UNDIRECTED;
// self->_type = GRAPH_DIRECTED;
self->_iter.hasnext = graph_iter_hasnext;
self->_iter.next = graph_iter_next;
self->_destory = graph_destory;
// -------------------- public --------------------
// kernel
// -> vertex
self->add_vertex = graph_add_vertex;
self->del_vertex = graph_del_vertex;
self->find_vertex = graph_find_vertex;
// -> edge
self->add_edge = graph_add_edge;
self->del_edge = graph_del_edge;
self->find_edge = graph_find_edge;
// base
self->size = graph_size;
self->clear = graph_clear;
self->empty = graph_empty;
self->capacity = graph_capacity;
// iter
self->iter = graph_iter;
// others
self->from_matrix = NULL;
self->compare = NULL;
// -------------------- debug --------------------
self->print_obj = NULL;
self->print = graph_print;
return true;
}
graph_t graph_new(uint32_t obj_size)
{
graph_t graph = NULL;
graph = malloc(sizeof(struct _graph));
if (graph == NULL)
{
return NULL;
}
if (graph_init(graph, obj_size) != true)
{
free(graph);
return NULL;
}
return graph;
}
void graph_free(graph_t *graph)
{
if (graph == NULL || *graph == NULL)
{
return;
}
(*graph)->_destory(*graph);
free(*graph); free(*graph);
*graph = NULL; *graph = NULL;
} }

View File

@ -12,12 +12,171 @@
void test_graph_new(void) void test_graph_new(void)
{ {
graph_t graph = graph_new2(sizeof(int), 10); graph_t graph = graph_new(sizeof(int));
TEST_ASSERT_NOT_NULL(graph); TEST_ASSERT_NOT_NULL(graph);
graph_free(&graph); graph_free(&graph);
TEST_ASSERT_NULL(graph); TEST_ASSERT_NULL(graph);
} }
void test_graph_add_vertex(void)
{
const int size = 10;
int data[10] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
};
int temp = 11;
uint32_t i = 0;
graph_t graph = graph_new(sizeof(int));
TEST_ASSERT_NOT_NULL(graph);
graph->compare = compare_num;
graph->print_obj = print_num;
// test add_vertex
for(i = 0; i < size; i++)
{
TEST_ASSERT_TRUE(graph->add_vertex(graph, &data[i]));
}
// graph->print(graph);
// test find_vertex
TEST_ASSERT_TRUE(graph->find_vertex(graph, &data[0]));
TEST_ASSERT_TRUE(graph->find_vertex(graph, &data[9]));
TEST_ASSERT_FALSE(graph->find_vertex(graph, &temp));
// test del_vertex
TEST_ASSERT_TRUE(graph->del_vertex(graph, &data[0]));
TEST_ASSERT_FALSE(graph->find_vertex(graph, &data[0]));
// graph->print(graph);
for(i = 1; i < size; i++)
{
TEST_ASSERT_TRUE(graph->del_vertex(graph, &data[i]));
}
TEST_ASSERT_TRUE(graph->empty(graph));
// test clear
for(i = 0; i < size; i++)
{
TEST_ASSERT_TRUE(graph->add_vertex(graph, &data[i]));
}
// graph->print(graph);
graph->clear(graph);
// graph->print(graph);
TEST_ASSERT_TRUE(graph->empty(graph));
graph_free(&graph);
TEST_ASSERT_NULL(graph);
}
void test_graph_add_edge(void)
{
const int size = 10;
int data[10] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
};
int temp = 11;
uint32_t i = 0;
graph_t graph = graph_new(sizeof(int));
TEST_ASSERT_NOT_NULL(graph);
graph->compare = compare_num;
graph->print_obj = print_num;
// test add_vertex
for(i = 0; i < size; i++)
{
TEST_ASSERT_TRUE(graph->add_vertex(graph, &data[i]));
}
//graph->print(graph);
// test add_edge
TEST_ASSERT_TRUE(graph->add_edge(graph, &data[0], &data[1], 12));
TEST_ASSERT_TRUE(graph->add_edge(graph, &data[0], &data[2], 13));
TEST_ASSERT_TRUE(graph->add_edge(graph, &data[1], &data[3], 24));
TEST_ASSERT_TRUE(graph->add_edge(graph, &data[5], &data[6], 67));
TEST_ASSERT_FALSE(graph->add_edge(graph, &temp, &data[1], 0));
//graph->print(graph);
// test find_edge
TEST_ASSERT_TRUE(graph->find_edge(graph, &data[0], &data[1]));
TEST_ASSERT_TRUE(graph->find_edge(graph, &data[1], &data[3]));
// TEST_ASSERT_TRUE(graph->find_edge(graph, &data[6], &data[5])); // undirected graph
TEST_ASSERT_FALSE(graph->find_edge(graph, &data[4], &data[3]));
TEST_ASSERT_FALSE(graph->find_edge(graph, &data[0], &temp));
// test del_edge
TEST_ASSERT_TRUE(graph->del_edge(graph, &data[0], &data[1]));
//graph->print(graph);
TEST_ASSERT_FALSE(graph->find_edge(graph, &data[0], &data[1]));
TEST_ASSERT_TRUE(graph->del_edge(graph, &data[5], &data[6]));
//graph->print(graph);
graph_free(&graph);
TEST_ASSERT_NULL(graph);
}
void test_graph_iter(void)
{
const int size = 10;
int data[10] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
};
int temp = 11;
uint32_t i = 0;
graph_t graph = graph_new(sizeof(int));
TEST_ASSERT_NOT_NULL(graph);
graph->compare = compare_num;
graph->print_obj = print_num;
// test add_vertex
for(i = 0; i < size; i++)
{
TEST_ASSERT_TRUE(graph->add_vertex(graph, &data[i]));
}
// graph->print(graph);
// test add_edge
TEST_ASSERT_TRUE(graph->add_edge(graph, &data[0], &data[1], 12));
TEST_ASSERT_TRUE(graph->add_edge(graph, &data[0], &data[2], 13));
TEST_ASSERT_TRUE(graph->add_edge(graph, &data[1], &data[3], 24));
TEST_ASSERT_TRUE(graph->add_edge(graph, &data[5], &data[6], 67));
TEST_ASSERT_TRUE(graph->add_edge(graph, &data[7], &data[6], 87));
TEST_ASSERT_TRUE(graph->add_edge(graph, &data[8], &data[2], 92));
TEST_ASSERT_FALSE(graph->add_edge(graph, &temp, &data[1], 0));
graph->print(graph);
iterator_t iter_vertex = NULL;
iter_vertex = graph->iter(graph, GRAPH_BFS, &data[0]);
TEST_ASSERT_NOT_NULL(iter_vertex);
while(iter_vertex->hasnext(iter_vertex))
{
temp = *(int *)iter_vertex->next(iter_vertex);
graph->print_obj(&temp);
}
printf("\n");
iter_vertex = graph->iter(graph, GRAPH_DFS, &data[0]);
TEST_ASSERT_NOT_NULL(iter_vertex);
while(iter_vertex->hasnext(iter_vertex))
{
temp = *(int *)iter_vertex->next(iter_vertex);
graph->print_obj(&temp);
}
printf("\n");
graph_free(&graph);
TEST_ASSERT_NULL(graph);
}
#if 0
void test_graph_print(void) void test_graph_print(void)
{ {
graph_t graph = graph_new2(sizeof(int), 10); graph_t graph = graph_new2(sizeof(int), 10);
@ -56,12 +215,17 @@ void test_graph_from_matrix(void)
graph_free(&graph); graph_free(&graph);
TEST_ASSERT_NULL(graph); TEST_ASSERT_NULL(graph);
} }
#endif
void test_graph(void) void test_graph(void)
{ {
UnitySetTestFile(__FILE__); UnitySetTestFile(__FILE__);
RUN_TEST(test_graph_new); RUN_TEST(test_graph_new);
RUN_TEST(test_graph_add_vertex);
RUN_TEST(test_graph_add_edge);
RUN_TEST(test_graph_iter);
// RUN_TEST(test_graph_print); // RUN_TEST(test_graph_print);
// RUN_TEST(test_graph_from_matrix); // RUN_TEST(test_graph_from_matrix);
} }