joe 4 年之前
当前提交
f251edb58d
共有 41 个文件被更改,包括 1069 次插入0 次删除
  1. 3 0
      .gitignore
  2. 6 0
      CMakeLists.txt
  3. 26 0
      include/ds.h
  4. 26 0
      include/ds/array.h
  5. 9 0
      include/ds/avltree.h
  6. 46 0
      include/ds/bitree.h
  7. 8 0
      include/ds/bstree.h
  8. 10 0
      include/ds/clist.h
  9. 36 0
      include/ds/common.h
  10. 48 0
      include/ds/dlist.h
  11. 11 0
      include/ds/err.h
  12. 8 0
      include/ds/heap.h
  13. 56 0
      include/ds/list.h
  14. 7 0
      include/ds/pqueue.h
  15. 24 0
      include/ds/queue.h
  16. 7 0
      include/ds/rbtree.h
  17. 8 0
      include/ds/set.h
  18. 25 0
      include/ds/stack.h
  19. 8 0
      include/ds/vector.h
  20. 12 0
      include/ds/version.h
  21. 18 0
      src/CMakeLists.txt
  22. 76 0
      src/array.c
  23. 0 0
      src/avltree.c
  24. 194 0
      src/bitree.c
  25. 1 0
      src/clist.c
  26. 21 0
      src/common.c
  27. 128 0
      src/dlist.c
  28. 2 0
      src/heap.c
  29. 95 0
      src/list.c
  30. 2 0
      src/pqueue.c
  31. 12 0
      src/queue.c
  32. 2 0
      src/rbtree.c
  33. 0 0
      src/set.c
  34. 25 0
      src/stack.c
  35. 1 0
      src/vector.c
  36. 13 0
      test/CMakeLists.txt
  37. 17 0
      test/test.c
  38. 35 0
      test/test_bitree.h
  39. 15 0
      test/test_dlist.h
  40. 28 0
      test/test_list.h
  41. 二进制
      test/ut

+ 3 - 0
.gitignore

@@ -0,0 +1,3 @@
+bin/
+build/
+.vscode/

+ 6 - 0
CMakeLists.txt

@@ -0,0 +1,6 @@
+cmake_minimum_required(VERSION 3.2)
+
+project(dsp)
+
+add_subdirectory(src)
+add_subdirectory(test)

+ 26 - 0
include/ds.h

@@ -0,0 +1,26 @@
+#ifndef _DS_H_
+#define _DS_H_
+
+/**
+ * Data Structure Demo Version
+ * Non-Thread-Safe
+ * Author: yyk882002@gmail.com
+ * Date: 2020-12-15
+ * License: Public Domain, at one own's risk
+ */
+#include <ds/version.h>
+
+#include <ds/list.h>
+#include <ds/dlist.h>
+#include <ds/clist.h>
+#include <ds/stack.h>
+#include <ds/queue.h>
+#include <ds/array.h>
+#include <ds/version.h>
+#include <ds/set.h>
+#include <ds/bitree.h>
+#include <ds/bstree.h>
+#include <ds/rbtree.h>
+#include <ds/heap.h>
+
+#endif

+ 26 - 0
include/ds/array.h

@@ -0,0 +1,26 @@
+#ifndef _DS_ARRAY_H_
+#define _DS_ARRAY_H_
+
+/**
+ * array
+ */
+
+#include "common.h"
+
+typedef struct ds_array_t {
+  int size;
+  func_destroyer destroyer;
+  ds_data_t *ptr;
+}ds_array_t;
+
+ds_array_t *  ds_array_init(func_destroyer destroyer, int size);
+void          ds_array_destroy(ds_array_t* arr);
+
+int           ds_array_get(ds_array_t* arr, int pos, ds_data_t* data);
+int           ds_array_set(ds_array_t* arr, int pos, ds_data_t data);
+
+int           ds_array_fill(ds_array_t* arr, ds_data_t data);
+
+#define ds_array_size(arr) ((arr)->size)
+
+#endif

+ 9 - 0
include/ds/avltree.h

@@ -0,0 +1,9 @@
+#ifndef _DS_AVLTREE_H_
+#define _DS_AVLTREE_H_
+
+/**
+ * AVL Tree
+ * Self-balancing bianry tree
+ */
+
+#endif

+ 46 - 0
include/ds/bitree.h

@@ -0,0 +1,46 @@
+#ifndef _DS_BITREE_H_
+#define _DS_BITREE_H_
+
+/**
+ * binary tree implementation
+ */
+#include "common.h"
+
+typedef struct ds_bitree_node_t {
+  ds_data_t data;
+  struct ds_bitree_node_t* left;
+  struct ds_bitree_node_t* right;
+}ds_bitree_node_t;
+
+typedef struct ds_bitree_t {
+  int size;
+  ds_bitree_node_t* root;
+  func_destroyer destroyer;
+  func_comparer comparer;
+}ds_bitree_t;
+
+ds_bitree_t* ds_bitree_init(func_destroyer destroyer);
+void ds_bitree_destroy(ds_bitree_t* tree);
+
+int ds_bitree_ins_left(ds_bitree_t* tree, ds_bitree_node_t* node, ds_data_t data);
+int ds_bitree_ins_right(ds_bitree_t* tree, ds_bitree_node_t* node, ds_data_t data);
+
+int ds_bitree_rm_left(ds_bitree_t* tree, ds_bitree_node_t* node);
+int ds_bitree_rm_right(ds_bitree_t* tree, ds_bitree_node_t* node);
+
+ds_bitree_t* ds_bitree_merge(ds_bitree_t*left, ds_bitree_t*right, ds_data_t data);
+
+void ds_bitree_preorder(ds_bitree_node_t* node, func_each each);
+void ds_bitree_inorder(ds_bitree_node_t* node, func_each each);
+void ds_bitree_postorder(ds_bitree_node_t* node, func_each each);
+
+#define ds_bitree_size(tree) ((tree)->size)
+#define ds_bitree_root(tree) ((tree)->root)
+// is end-of-branch
+#define ds_bitree_is_eob(node) ((node) == NULL)
+#define ds_bitree_is_leaf(ndoe) ((node)->left == NULL && (node)->right == NULL)
+#define ds_bitree_data(node) ((node)->data)
+#define ds_bitree_left(node) ((node)->left)
+#define ds_bitree_right(node) ((node)->right)
+
+#endif

+ 8 - 0
include/ds/bstree.h

@@ -0,0 +1,8 @@
+#ifndef _DS_BSTREE_H_
+#define _DS_BSTREE_H_
+
+/**
+ * Binary Search Tree
+ */
+
+#endif

+ 10 - 0
include/ds/clist.h

@@ -0,0 +1,10 @@
+#ifndef _DS_CIRCLE_LIST_H_
+#define _DS_CIRCLE_LIST_H_
+
+/**
+ * circle linked list
+ */
+#include "common.h"
+
+
+#endif  // clist.h

+ 36 - 0
include/ds/common.h

@@ -0,0 +1,36 @@
+#ifndef _DS_COMMON_H_
+#define _DS_COMMON_H_
+
+#include <stdlib.h>
+
+// data type
+typedef void* ds_data_t;
+
+// function used for traversal a container
+typedef void (*func_each)(void*);
+typedef void (*func_destroyer)(ds_data_t);
+// function used for comparing two values
+typedef int (*func_comparer)(ds_data_t, ds_data_t);
+typedef int (*func_foreach)(func_each cb);
+typedef int (*func_sort)(func_comparer comparer);
+
+// memory
+typedef void* (*func_malloc)(size_t);
+typedef void (*func_free)(void* ptr);
+
+// install new mem-allocate function
+void ds_setup(func_malloc m, func_free f);
+
+// default implementings of useful functions
+void ds_cb_default_destroyer(ds_data_t);
+void ds_cb_default_each(ds_data_t);
+int ds_cb_default_comparer(ds_data_t, ds_data_t);
+
+#define IMPL_FOREACH \
+  (void*)0
+
+#define UNUSED(x) (void)(x)
+
+#define DEF_ARRAY_SIZE 32
+
+#endif

+ 48 - 0
include/ds/dlist.h

@@ -0,0 +1,48 @@
+#ifndef _DS_DOUBLE_LINKED_LIST_H_
+#define _DS_DOUBLE_LINKED_LIST_H_
+
+#include "common.h"
+
+/**
+ * double linked list
+ */
+typedef struct ds_dlist_elem_t {
+  ds_data_t data;
+  struct ds_dlist_elem_t *prev;
+  struct ds_dlist_elem_t *next;
+}ds_dlist_elem_t;
+
+typedef struct ds_dlist_t {
+  int size;
+  func_comparer comparer;
+  func_destroyer destroyer;
+  ds_dlist_elem_t* head;
+  ds_dlist_elem_t* tail;
+}ds_dlist_t;
+
+// APIs
+ds_dlist_t* ds_dlist_init(func_destroyer destroyer);
+void        ds_dlist_destroy(ds_dlist_t* lst);
+
+/**
+ * insert data after elem
+ */
+int         ds_dlist_ins_next(ds_dlist_t* lst, ds_dlist_elem_t* elem, ds_data_t data);
+/**
+ * insert data before elem
+ */
+int         ds_dlist_ins_prev(ds_dlist_t* lst, ds_dlist_elem_t* elem, ds_data_t data);
+
+// remove node `elem`
+int         ds_dlist_rm(ds_dlist_t* lst, ds_dlist_elem_t* elem);
+
+#define ds_dlist_size(lst) ((lst)->size)
+#define ds_dlist_head(lst) ((lst)->head)
+#define ds_dlist_tail(lst) ((lst)->tail)
+#define ds_dlist_is_head(elem) ((elem)->prev == NULL ? 1 : 0)
+#define ds_dlist_is_tail(elem) ((elem)->next == NULL ? 1 : 0)
+#define ds_dlist_data(elem) ((elem)->data)
+#define ds_dlist_next(elem) ((elem)->next)
+#define ds_dlist_prev(elem) ((elem)->prev)
+
+#endif  // dlist.h

+ 11 - 0
include/ds/err.h

@@ -0,0 +1,11 @@
+#ifndef _DS_ERR_H_
+#define _DS_ERR_H_
+
+/* error code definition */
+#define DS_ERR_OK     0
+#define DS_ERR_MEM    -1
+#define DS_ERR_EMPTY  -2
+#define DS_ERR_TARGET_NOT_FOUND -3
+#define DS_ERR_PARAMS -4
+#define DS_ERR_TARGET_EXISTS  -5
+#endif

+ 8 - 0
include/ds/heap.h

@@ -0,0 +1,8 @@
+#ifndef _DS_HEAP_H_
+#define _DS_HEAP_H_
+
+/**
+ * Heap
+ */
+
+#endif

+ 56 - 0
include/ds/list.h

@@ -0,0 +1,56 @@
+#ifndef _DS_LIST_H_
+#define _DS_LIST_H_
+
+#include "common.h"
+
+/**
+ * single linked list
+ */
+
+// element of list
+typedef struct ds_list_elem_t {
+  ds_data_t data;
+  struct ds_list_elem_t *next;
+} ds_list_elem_t;
+
+// a list
+typedef struct ds_list_t {
+  int size;     // size of a list object
+  func_comparer comparer;
+  func_destroyer destroyer;
+  ds_list_elem_t *head;
+  ds_list_elem_t *tail;
+} ds_list_t;
+
+/* initialize a list object. return null if failed. */
+ds_list_t * ds_list_init(func_destroyer destroyer);
+
+/* destroy a list object and free its resources */
+void        ds_list_destroy(ds_list_t *lst);
+
+/**
+ * insert an element with `data` as its data field after `elem` node.
+ * if `elem` is null, isert `data` as list head
+ * return -1 if failed.
+ */
+int         ds_list_ins_next(ds_list_t *lst, ds_list_elem_t *elem,
+                     const ds_data_t data);
+
+/**
+ * remove an element after `elem` node.
+ * if `elem` is null, then remove head node.
+ * 
+ * return -1 if no node removed.
+ */
+int         ds_list_rm_next(ds_list_t *lst, ds_list_elem_t *elem, ds_data_t *data);
+
+/** functions below are easy to understand */
+#define ds_list_size(lst) ((lst)->size)
+#define ds_list_head(lst) ((lst)->head)
+#define ds_list_tail(lst) ((lst)->tail)
+#define ds_list_is_head(lst, elem) ((elem) == (lst)->head ? 1 : 0)
+#define ds_list_is_tail(lst, elem) ((elem) == (lst)->tail ? 1 : 0)
+#define ds_list_data(elem) ((elem)->data)
+#define ds_list_next(elem) ((elem)->next)
+
+#endif  // list.h

+ 7 - 0
include/ds/pqueue.h

@@ -0,0 +1,7 @@
+#ifndef _DS_PQUEUE_H_
+#define _DS_PQUEUE_H_
+
+/**
+ * priority queue
+ */
+#endif

+ 24 - 0
include/ds/queue.h

@@ -0,0 +1,24 @@
+#ifndef _DS_QUEUE_H_
+#define _DS_QUEUE_H_
+
+/**
+ * Queue
+ */
+#include "stack.h"
+
+typedef ds_list_t ds_queue_t;
+typedef ds_list_elem_t ds_queue_elem_t;
+
+/** initialize & destroy */
+#define ds_queue_init ds_list_init
+#define ds_queue_destroy ds_list_destory
+
+/** enqueue & dequeue */
+int     ds_queue_enq(ds_queue_t* q, ds_data_t data);
+int     ds_queue_deq(ds_queue_t* q, ds_data_t* data);
+
+/** query head & size */
+#define ds_queue_peek ds_stack_peek
+#define ds_queue_size ds_list_size
+
+#endif

+ 7 - 0
include/ds/rbtree.h

@@ -0,0 +1,7 @@
+#ifndef _DS_RBTREE_H_
+#define _DS_RBTREE_H_
+
+/**
+ * Red black tree
+ */
+#endif

+ 8 - 0
include/ds/set.h

@@ -0,0 +1,8 @@
+#ifndef _DS_SET_H_
+#define _DS_SET_H_
+
+/**
+ * Set
+ */
+
+#endif

+ 25 - 0
include/ds/stack.h

@@ -0,0 +1,25 @@
+#ifndef _DS_STACK_H_
+#define _DS_STACK_H_
+
+/**
+ * Stack
+ */
+#include "list.h"
+
+typedef ds_list_t ds_stack_t;
+typedef ds_list_elem_t ds_stack_elem_t;
+
+/** initialize & destroy */
+#define ds_stack_init ds_list_init
+#define ds_stack_destroy ds_list_destroy
+
+/** push & pop */
+int     ds_stack_push(ds_stack_t* s, ds_data_t data);
+int     ds_stack_pop(ds_stack_t* s, ds_data_t *data);
+
+/** query top & size */
+int     ds_stack_peek(ds_stack_t* s, ds_data_t *data);
+
+#define ds_stack_size ds_list_size
+
+#endif

+ 8 - 0
include/ds/vector.h

@@ -0,0 +1,8 @@
+#ifndef _DS_VECTOR_H_
+#define _DS_VECTOR_H_
+
+/**
+ * Vector
+ */
+
+#endif  // vector

+ 12 - 0
include/ds/version.h

@@ -0,0 +1,12 @@
+#ifndef _DS_VERSION_H_
+#define _DS_VERSION_H_
+
+#define DS_VERSION_MAJOR 0
+#define DS_VERSION_MINOR 0
+#define DS_VERSION_PATCH 1
+#define DS_VERSION_IS_RELEASE 0
+
+#define DS_VERSION_HEX \
+  ((DS_VERSION_MAJOR << 16) | (DS_VERSION_MINOR << 8) | (DS_VERSION_PATCH << 0))
+
+#endif

+ 18 - 0
src/CMakeLists.txt

@@ -0,0 +1,18 @@
+cmake_minimum_required(VERSION 3.2)
+
+project(ds C)
+
+message("Project name: " ${PROJECT_NAME})
+message("source dir:" ${PROJECT_SOURCE_DIR})
+
+set(CMAKE_C_STANDARD 99)
+set(CMAKE_C_FLAG "-g -Wall")
+set(LIBRARY_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../build)
+
+include_directories(${PROJECT_SOURCE_DIR}/../include)
+
+# file(GLOB_RECURSE c_files ${PROJECT_SOURCE_DIR}/src/*.c)
+
+aux_source_directory(${PROJECT_SOURCE_DIR} DIR_SRCS)
+
+add_library(${PROJECT_NAME} ${DIR_SRCS})

+ 76 - 0
src/array.c

@@ -0,0 +1,76 @@
+#include <ds/array.h>
+#include <ds/err.h>
+
+extern func_malloc ds_malloc;
+extern func_free ds_free;
+
+ds_array_t*  ds_array_init(func_destroyer destroyer, int size)
+{
+  ds_array_t* arr = (ds_array_t*)ds_malloc(sizeof(ds_array_t));
+  if (!arr) {
+    return NULL;
+  }
+
+  if(size <= 0) {
+    size = DEF_ARRAY_SIZE;
+  }
+  arr->ptr = (ds_data_t*)ds_malloc(sizeof(ds_data_t) * size);
+  if(!arr->ptr) {
+    ds_free(arr);
+    return NULL;
+  }
+  arr->destroyer = destroyer;
+  return arr;
+}
+
+void ds_array_destroy(ds_array_t* arr)
+{
+  int i;
+  if(!arr) {
+    return;
+  }
+  for(i=0; i<arr->size; i++) {
+    if(arr->destroyer) {
+      arr->destroyer(arr->ptr+i);
+    }
+  }
+}
+
+int ds_array_get(ds_array_t* arr, int pos, ds_data_t* data)
+{
+  if(!arr) {
+    return DS_ERR_PARAMS;
+  }
+  if(pos >= arr->size){
+    return DS_ERR_PARAMS;
+  }
+  if(data){
+    *data = arr->ptr + pos;
+  }
+  return DS_ERR_OK;
+}
+
+int ds_array_set(ds_array_t* arr, int pos, ds_data_t data)
+{
+  if(!arr) {
+    return DS_ERR_PARAMS;
+  }
+  if(pos >= arr->size){
+    return DS_ERR_PARAMS;
+  }
+  arr->ptr[pos] = data;
+  return DS_ERR_OK;
+}
+
+int ds_array_fill(ds_array_t* arr, ds_data_t data)
+{
+  if(!arr) {
+    return DS_ERR_PARAMS;
+  }
+  int i;
+  for (i=0; i<arr->size; i++){
+    arr->ptr[i] = data;
+  }
+
+  return DS_ERR_OK;
+}

+ 0 - 0
src/avltree.c


+ 194 - 0
src/bitree.c

@@ -0,0 +1,194 @@
+#include <ds/bitree.h>
+#include <ds/err.h>
+
+extern func_malloc ds_malloc;
+extern func_free ds_free;
+
+ds_bitree_t* ds_bitree_init(func_each destroyer)
+{
+  ds_bitree_t* tree = (ds_bitree_t*)ds_malloc(sizeof(ds_bitree_t));
+  if (!tree) {
+    return NULL;
+  }
+  tree->size = 0;
+  tree->root = NULL;
+  tree->destroyer = destroyer;
+  tree->comparer = NULL;
+  return tree;
+}
+
+void ds_bitree_destroy(ds_bitree_t* tree)
+{
+  ds_bitree_rm_left(tree, NULL);
+
+  ds_free(tree);
+  tree = NULL;
+}
+
+int ds_bitree_ins_left(ds_bitree_t* tree, ds_bitree_node_t* node, ds_data_t data)
+{
+  ds_bitree_node_t * new_node, **pos;
+  if (!node) {
+    if (ds_bitree_size(tree) > 0) {
+      return DS_ERR_PARAMS;
+    }
+    pos = &(tree->root);
+  } else {
+    if (ds_bitree_left(node)) {
+      return DS_ERR_TARGET_EXISTS;
+    }
+    pos = &(node->left);
+  }
+  if((new_node = (ds_bitree_node_t*)ds_malloc(sizeof(ds_bitree_node_t))) == NULL) {
+    return DS_ERR_MEM;
+  }
+
+  new_node->data = data;
+  new_node->left = NULL;
+  new_node->right = NULL;
+
+  *pos = new_node;
+  tree->size++;
+
+  return DS_ERR_OK;
+}
+
+int ds_bitree_ins_right(ds_bitree_t* tree, ds_bitree_node_t* node, ds_data_t data)
+{
+  ds_bitree_node_t * new_node, **pos;
+  if (!node) {
+    if (ds_bitree_size(tree) > 0) {
+      return DS_ERR_PARAMS;
+    }
+    pos = &tree->root;
+  } else {
+    if (ds_bitree_right(node)) {
+      return DS_ERR_TARGET_EXISTS;
+    }
+    pos = &(node->right);
+  }
+  if((new_node = (ds_bitree_node_t*)ds_malloc(sizeof(ds_bitree_node_t))) == NULL) {
+    return DS_ERR_MEM;
+  }
+
+  new_node->data = data;
+  new_node->left = NULL;
+  new_node->right = NULL;
+
+  *pos = new_node;
+  tree->size++;
+
+  return DS_ERR_OK;
+}
+
+int ds_bitree_rm_left(ds_bitree_t* tree, ds_bitree_node_t* node)
+{
+  ds_bitree_node_t ** pos;
+  if (ds_bitree_size(tree) <= 0) {
+    return DS_ERR_EMPTY;
+  }
+  if (!node) {
+    pos = &(tree->root);
+  } else {
+    pos = &(node->left);
+  }
+
+  if (*pos) {
+    ds_bitree_rm_left(tree, *pos);
+    ds_bitree_rm_right(tree, *pos);
+
+    if(tree->destroyer) {
+      tree->destroyer((*pos)->data);
+    }
+
+    ds_free(*pos);
+    *pos = NULL;
+
+    tree->size--;
+  }
+  return DS_ERR_OK;
+}
+
+int ds_bitree_rm_right(ds_bitree_t* tree, ds_bitree_node_t* node)
+{
+  ds_bitree_node_t**pos;
+  if (ds_bitree_size(tree) <= 0){
+    return DS_ERR_EMPTY;
+  }
+  if(!node) {
+    pos = &(tree->root);
+  } else {
+    pos = &(node->right);
+  }
+
+  if (*pos) {
+    ds_bitree_rm_left(tree, *pos);
+    ds_bitree_rm_right(tree, *pos);
+
+    if(tree->destroyer){
+      tree->destroyer((*pos)->data);
+    }
+
+    ds_free(*pos);
+    *pos = NULL;
+
+    tree->size--;
+  }
+  return DS_ERR_OK;
+}
+
+ds_bitree_t* ds_bitree_merge(ds_bitree_t*left, ds_bitree_t*right, ds_data_t data)
+{
+  ds_bitree_t *new_tree = ds_bitree_init(left->destroyer);
+  if(!new_tree) {
+    return NULL;
+  }
+  int err;
+  if((err = ds_bitree_ins_left(new_tree, NULL, data)) != DS_ERR_OK) {
+    ds_bitree_destroy(new_tree);
+    return NULL;
+  }
+
+  ds_bitree_root(new_tree)->left = ds_bitree_root(left);
+  ds_bitree_root(new_tree)->right = ds_bitree_root(right);
+
+  new_tree->size = new_tree->size + left->size + right->size;
+
+  ds_free(left);
+  ds_free(right);
+
+  return new_tree;
+}
+
+void ds_bitree_preorder(ds_bitree_node_t* node, func_each each)
+{
+  if(node){
+    if(each){
+      each(node);
+    }
+    ds_bitree_preorder(node->left, each);
+    ds_bitree_preorder(node->right, each);
+  }
+}
+
+void ds_bitree_inorder(ds_bitree_node_t* node, func_each each)
+{
+  if(node) {
+    ds_bitree_inorder(node->left, each);
+    if(each){
+      each(node);
+    }
+    ds_bitree_inorder(node->right, each);
+  }
+}
+
+void ds_bitree_postorder(ds_bitree_node_t* node, func_each each)
+{
+  if(node) {
+    ds_bitree_postorder(node->left, each);
+    ds_bitree_postorder(node->right, each);
+    if(each){
+      each(node);
+    }
+  }
+}

+ 1 - 0
src/clist.c

@@ -0,0 +1 @@
+#include <ds/clist.h>

+ 21 - 0
src/common.c

@@ -0,0 +1,21 @@
+#include <ds/common.h>
+#include <memory.h>
+
+func_malloc ds_malloc = malloc;
+func_free ds_free = free;
+
+void ds_setup(func_malloc m, func_free f){
+  ds_malloc = m;
+  ds_free = f;
+}
+
+void ds_cb_default_destroyer(ds_data_t data){
+  ds_free(data);
+  data = NULL;
+}
+
+void ds_cb_default_each(ds_data_t data) {}
+
+int ds_cb_default_comparer(ds_data_t left, ds_data_t right) {
+  return left == right;
+}

+ 128 - 0
src/dlist.c

@@ -0,0 +1,128 @@
+#include <ds/dlist.h>
+#include <ds/err.h>
+
+extern func_malloc ds_malloc;
+extern func_free ds_free;
+
+ds_dlist_t* ds_dlist_init(func_destroyer destroyer)
+{
+  ds_dlist_t* lst = (ds_dlist_t*)ds_malloc(sizeof(ds_dlist_t));
+  if (!lst) {
+    return NULL;
+  }
+
+  lst->comparer = NULL;
+  lst->destroyer = destroyer;
+  lst->size = 0;
+  lst->head = NULL;
+  lst->tail = NULL;
+
+  return lst;
+}
+
+void ds_dlist_destroy(ds_dlist_t* lst)
+{
+  while(ds_dlist_size(lst) > 0) {
+    ds_dlist_rm(lst, ds_dlist_head(lst));
+  }
+}
+
+int ds_dlist_ins_next(ds_dlist_t* lst, ds_dlist_elem_t* elem, ds_data_t data)
+{
+  ds_dlist_elem_t* new_elem;
+  if(!elem && ds_dlist_size(lst) > 0) {
+    return DS_ERR_PARAMS;
+  }
+  if((new_elem = (ds_dlist_elem_t*)ds_malloc(sizeof(ds_dlist_elem_t))) == NULL){
+    return DS_ERR_MEM;
+  }
+  new_elem->data = data;
+
+  if(elem) {
+    new_elem->next = elem->next;
+    new_elem->prev = elem;
+    if(elem->next) {
+      elem->next->prev = new_elem;
+    }else{
+      lst->tail = new_elem;
+    }
+    elem->next = new_elem;
+  } else { // empty
+    new_elem->next = NULL;
+    new_elem->prev = NULL;
+    lst->head = new_elem;
+    lst->tail = new_elem;
+  }
+
+  lst->size++;
+
+  return DS_ERR_OK;
+}
+
+int ds_dlist_ins_prev(ds_dlist_t* lst, ds_dlist_elem_t* elem, ds_data_t data)
+{
+  ds_dlist_elem_t* new_elem;
+  if(!elem && ds_dlist_size(lst) > 0) {
+    return DS_ERR_PARAMS;
+  }
+
+  if((new_elem = (ds_dlist_elem_t*)ds_malloc(sizeof(ds_dlist_elem_t))) == NULL) {
+    return DS_ERR_MEM;
+  }
+
+  if(elem) {
+    new_elem->next = elem;
+    new_elem->prev = elem->prev;
+
+    if(elem->prev) {
+        elem->prev->next = new_elem;
+    } else { // insert as head
+      lst->head = new_elem;
+    }
+    elem->prev = new_elem;
+  } else {  // empty
+    new_elem->next = NULL;
+    new_elem->prev = NULL;
+    lst->head = new_elem;
+    lst->tail = new_elem;
+  }
+
+  lst->size++;
+
+  return DS_ERR_OK;
+}
+
+int ds_dlist_rm(ds_dlist_t* lst, ds_dlist_elem_t* elem)
+{
+  if (!elem) {
+    return DS_ERR_PARAMS;
+  }
+  if(ds_dlist_size(lst) <= 0){
+    return DS_ERR_EMPTY;
+  }
+
+  if (lst->head == elem) {
+    lst->head = elem->next;
+    if (elem->next == NULL) {
+        lst->tail = NULL;
+    } else {
+        elem->next->prev = elem->prev; // should be NULL
+    }
+  } else {
+    elem->prev->next = elem->next;
+    if (elem->next == NULL) { // tail node
+      lst->tail = elem->prev;
+    } else {
+      elem->next->prev = elem->prev;
+    }
+  }
+
+  if(lst->destroyer) {
+    lst->destroyer(ds_dlist_data(elem));
+  }
+  ds_free(elem);
+  
+  lst->size--;
+
+  return DS_ERR_OK;
+}

+ 2 - 0
src/heap.c

@@ -0,0 +1,2 @@
+#include <ds/heap.h>
+#include <ds/err.h>

+ 95 - 0
src/list.c

@@ -0,0 +1,95 @@
+#include <ds/list.h>
+#include <ds/err.h>
+
+extern func_malloc ds_malloc;
+extern func_free ds_free;
+
+ds_list_t *ds_list_init(func_destroyer destroyer) {
+  ds_list_t *lst = (ds_list_t *)ds_malloc(sizeof(ds_list_t));
+  if (!lst) {
+    return NULL;
+  }
+  lst->size = 0;
+  lst->head = NULL;
+  lst->tail = NULL;
+  lst->comparer = NULL;
+  lst->destroyer = destroyer;
+  return lst;
+}
+
+void ds_list_destroy(ds_list_t *lst) {
+  ds_data_t data;
+
+  while (lst->size > 0) {
+    ds_list_rm_next(lst, NULL, &data);
+    if(lst->destroyer) {
+      lst->destroyer(data);
+    }
+  }
+}
+
+int ds_list_ins_next(ds_list_t *lst, ds_list_elem_t *elem,
+                     const ds_data_t data) {
+  ds_list_elem_t *new_elem =
+      (ds_list_elem_t *)ds_malloc(sizeof(ds_list_elem_t));
+  if (new_elem == NULL) {
+    return DS_ERR_MEM;
+  }
+  new_elem->data = data;
+
+  if (elem == NULL) {
+    // insert as head
+    if (ds_list_size(lst) <= 0) {
+      lst->tail = new_elem;
+    }
+    new_elem->next = lst->head;
+    lst->head = new_elem;
+  } else {
+    if (elem->next == NULL) {
+      lst->tail = new_elem;
+    }
+    new_elem->next = elem->next;
+    elem->next = new_elem;
+  }
+
+  lst->size++;
+
+  return DS_ERR_OK;
+}
+
+int ds_list_rm_next(ds_list_t *lst, ds_list_elem_t *elem, ds_data_t *data) {
+  ds_list_elem_t *old;  // element to be remove
+  
+  if (ds_list_size(lst) <= 0) {
+    return DS_ERR_EMPTY;
+  }
+
+  if (!elem) {
+    old = lst->head;
+    lst->head = old->next;
+    // the last element?
+    if (ds_list_size(lst) == 1) {
+      lst->tail = NULL;
+    }
+  } else {
+    if (elem->next == NULL) {
+      return DS_ERR_TARGET_NOT_FOUND;
+    }
+    old = elem->next;
+    elem->next = old->next;
+    // removing the tail ?
+    if (elem->next == NULL) {
+      lst->tail = elem;
+    }
+  }
+  
+  if(data) {
+    *data = ds_list_data(old);
+  }
+  
+  ds_free(old);
+
+  lst->size--;
+  // assert(lst->size >= 0);
+  return DS_ERR_OK;
+}

+ 2 - 0
src/pqueue.c

@@ -0,0 +1,2 @@
+#include <ds/pqueue.h>
+#include <ds/err.h>

+ 12 - 0
src/queue.c

@@ -0,0 +1,12 @@
+#include <ds/queue.h>
+#include <ds/err.h>
+
+int ds_queue_enq(ds_queue_t* q, ds_data_t data)
+{
+  return ds_list_ins_next(q, ds_list_tail(q), data);
+}
+
+int ds_queue_deq(ds_queue_t* q, ds_data_t* data)
+{
+  return ds_list_rm_next(q, NULL, data);
+}

+ 2 - 0
src/rbtree.c

@@ -0,0 +1,2 @@
+#include <ds/rbtree.h>
+#include <ds/err.h>

+ 0 - 0
src/set.c


+ 25 - 0
src/stack.c

@@ -0,0 +1,25 @@
+#include <ds/stack.h>
+#include <ds/err.h>
+
+int ds_stack_push(ds_stack_t* s, ds_data_t data)
+{
+  return ds_list_ins_next(s, NULL, data);
+}
+
+int ds_stack_pop(ds_stack_t* s, ds_data_t *data)
+{
+  return ds_list_rm_next(s, NULL, data);
+}
+
+int ds_stack_peek(ds_stack_t* s, ds_data_t *data)
+{
+  if(ds_list_size(s) <= 0) {
+    return DS_ERR_EMPTY;
+  }
+  ds_list_elem_t*head = ds_list_head(s);
+  if(data) {
+    *data = head->data;
+  }
+  
+  return 0;
+}

+ 1 - 0
src/vector.c

@@ -0,0 +1 @@
+#include <ds/vector.h>

+ 13 - 0
test/CMakeLists.txt

@@ -0,0 +1,13 @@
+cmake_minimum_required(VERSION 3.2)
+
+project(utest C)
+
+set(CMAKE_C_STANDARD 99)
+set(CMAKE_C_FLAG "-g -Wall")
+set(EXECUTABLE_OUTPUT_PATH ${PROJECT_SOURCE_DIR}/../build)
+
+include_directories(${PROJECT_SOURCE_DIR}/../include)
+aux_source_directory(. DIR_SRC)
+
+add_executable(${PROJECT_NAME} ${DIR_SRC})
+target_link_libraries(${PROJECT_NAME} cmockery ds)

+ 17 - 0
test/test.c

@@ -0,0 +1,17 @@
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <google/cmockery.h>
+#include "test_list.h"
+#include "test_dlist.h"
+#include "test_bitree.h"
+
+int main() {
+  const UnitTest tests[] = {
+      unit_test(test_list_generally),
+      unit_test(test_dlist_generally),
+      unit_test(test_bitree_generally),
+  };
+  
+  return run_tests(tests);
+}

+ 35 - 0
test/test_bitree.h

@@ -0,0 +1,35 @@
+#ifndef TEST_BITREE_H
+#define TEST_BITREE_H
+
+
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <google/cmockery.h>
+#include <ds.h>
+
+void tree_printer(void* node){
+  ds_bitree_node_t* n = (ds_bitree_node_t*)node;
+  printf("%d\n", (int)ds_bitree_data(n));
+}
+
+void test_bitree_generally(void **state) {
+  ds_bitree_t* tree = ds_bitree_init(NULL);
+  ds_bitree_ins_left(tree, NULL, (ds_data_t)1);
+
+  ds_bitree_ins_left(tree, ds_bitree_root(tree), (ds_data_t)2);
+  ds_bitree_ins_right(tree, ds_bitree_root(tree), (ds_data_t)3);
+
+  assert_true(ds_bitree_size(tree) == 3);
+
+  ds_bitree_preorder(ds_bitree_root(tree), tree_printer);
+  ds_bitree_inorder(ds_bitree_root(tree), tree_printer);
+  ds_bitree_postorder(ds_bitree_root(tree), tree_printer);
+
+  ds_bitree_destroy(tree);
+
+  UNUSED(state);
+}
+
+#endif

+ 15 - 0
test/test_dlist.h

@@ -0,0 +1,15 @@
+#ifndef TEST_DLIST_H
+#define TEST_DLIST_H
+
+
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <google/cmockery.h>
+#include <ds.h>
+
+void test_dlist_generally(void **state) {
+  UNUSED(state);
+}
+
+#endif

+ 28 - 0
test/test_list.h

@@ -0,0 +1,28 @@
+#ifndef TEST_LIST_H
+#define TEST_LIST_H
+
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <google/cmockery.h>
+#include <ds.h>
+
+void test_list_generally(void **state) {
+  UNUSED(state);
+  int errno = 0;
+  ds_list_t* lst = ds_list_init(NULL);
+  // insert 1
+  errno = ds_list_ins_next(lst,NULL, (ds_data_t)1);
+  assert_true(errno == 0);
+  ds_list_elem_t* head = ds_list_head(lst);
+  assert_true(head != NULL);
+  assert_true(ds_list_data(head) == (ds_data_t)1);
+  assert_true(ds_list_size(lst) == 1);
+  // insert 2
+  // insert 3
+  // remove 1
+  // remove 2
+  ds_list_destroy(lst);
+}
+
+#endif

二进制
test/ut