双链表冒泡排序
This commit is contained in:
parent
1559d5941c
commit
2960ca4fd8
Binary file not shown.
|
@ -0,0 +1,264 @@
|
|||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#define MAX_DATA 512
|
||||
#define MAX_ROWS 100
|
||||
|
||||
struct Address {
|
||||
int id;
|
||||
int set;
|
||||
char name[MAX_DATA];
|
||||
char email[MAX_DATA];
|
||||
};
|
||||
|
||||
struct Database {
|
||||
struct Address rows[MAX_ROWS];
|
||||
};
|
||||
|
||||
struct Connection {
|
||||
FILE *file;
|
||||
struct Database *db;
|
||||
};
|
||||
|
||||
void die(const char *message)
|
||||
{
|
||||
if (errno)
|
||||
{
|
||||
perror(message);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("ERROR: %s\n", message);
|
||||
}
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void Address_print(struct Address *addr)
|
||||
{
|
||||
printf("%d %s %s\n", addr->id, addr->name, addr->email);
|
||||
}
|
||||
|
||||
void Database_load(struct Connection *conn)
|
||||
{
|
||||
int rc = fread(conn->db, sizeof(struct Database), 1, conn->file);
|
||||
if (rc != 1 )
|
||||
{
|
||||
die("Failed to load database.");
|
||||
}
|
||||
}
|
||||
|
||||
struct Connection *Database_open(const char *filename, char mode)
|
||||
{
|
||||
struct Connection *conn = malloc(sizeof(struct Connection));
|
||||
if (!conn)
|
||||
{
|
||||
die("Memory error");
|
||||
}
|
||||
|
||||
conn->db = malloc(sizeof(struct Database));
|
||||
if (!conn->db)
|
||||
{
|
||||
die("Memory error");
|
||||
}
|
||||
|
||||
if (mode == 'c')
|
||||
{
|
||||
conn->file = fopen(filename, "w");
|
||||
}
|
||||
else
|
||||
{
|
||||
conn->file = fopen(filename, "r+");
|
||||
|
||||
if (conn->file)
|
||||
{
|
||||
Database_load(conn);
|
||||
}
|
||||
}
|
||||
|
||||
if (!conn->file)
|
||||
{
|
||||
die("Failed to open the file");
|
||||
}
|
||||
|
||||
return conn;
|
||||
};
|
||||
|
||||
void Database_close(struct Connection *conn)
|
||||
{
|
||||
if (conn)
|
||||
{
|
||||
if (conn->file)
|
||||
{
|
||||
fclose(conn->file);
|
||||
}
|
||||
if (conn->db)
|
||||
{
|
||||
free(conn->db);
|
||||
}
|
||||
free(conn);
|
||||
}
|
||||
}
|
||||
|
||||
void Database_write(struct Connection *conn)
|
||||
{
|
||||
rewind(conn->file);
|
||||
|
||||
int rc = fwrite(conn->db, sizeof(struct Database), 1, conn->file);
|
||||
if (rc != 1)
|
||||
{
|
||||
die("Failed to write database.");
|
||||
}
|
||||
|
||||
rc = fflush(conn->file);
|
||||
if (rc == -1)
|
||||
{
|
||||
die("Cannot flush database.");
|
||||
}
|
||||
}
|
||||
|
||||
void Database_create(struct Connection *conn)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
for (i = 0; i < MAX_ROWS; i++)
|
||||
{
|
||||
// make a prototype to initialize it
|
||||
struct Address addr = {.id = i, .set = 0};
|
||||
// then just assign it
|
||||
conn->db->rows[i] = addr;
|
||||
}
|
||||
}
|
||||
|
||||
void Database_set(struct Connection *conn, int id, const char *name, const char *email)
|
||||
{
|
||||
struct Address *addr = &conn->db->rows[id];
|
||||
if (addr->set)
|
||||
{
|
||||
die("Already set, delete it first");
|
||||
}
|
||||
|
||||
addr->set = 1;
|
||||
// WARNING: bug, read the "How To Break It" and fix this
|
||||
char *res = strncpy(addr->name, name, MAX_DATA);
|
||||
// demonstrate the strncpy bug
|
||||
if (!res)
|
||||
{
|
||||
die("Name copy failed");
|
||||
}
|
||||
|
||||
res = strncpy(addr->email, email, MAX_DATA);
|
||||
if (!res)
|
||||
{
|
||||
die("Email copy failed");
|
||||
}
|
||||
}
|
||||
|
||||
void Database_get(struct Connection *conn, int id)
|
||||
{
|
||||
struct Address *addr = &conn->db->rows[id];
|
||||
|
||||
if (addr->set)
|
||||
{
|
||||
Address_print(addr);
|
||||
}
|
||||
else
|
||||
{
|
||||
die("ID is not set");
|
||||
}
|
||||
}
|
||||
|
||||
void Database_delete(struct Connection *conn, int id)
|
||||
{
|
||||
struct Address addr = {.id = id, .set = 0};
|
||||
conn->db->rows[id] = addr;
|
||||
}
|
||||
|
||||
void Database_list(struct Connection *conn)
|
||||
{
|
||||
int i = 0;
|
||||
struct Database *db = conn->db;
|
||||
|
||||
for (i = 0; i < MAX_ROWS; i++)
|
||||
{
|
||||
struct Address *cur = &db->rows[i];
|
||||
|
||||
if (cur->set)
|
||||
{
|
||||
Address_print(cur);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
if (argc < 3)
|
||||
{
|
||||
die("USAGE: ex17 <dbfile><action> [action params]");
|
||||
}
|
||||
|
||||
char *filename = argv[1];
|
||||
char action = argv[2][0];
|
||||
struct Connection *conn = Database_open(filename, action);
|
||||
int id = 0;
|
||||
|
||||
if (argc > 3)
|
||||
{
|
||||
id = atoi(argv[3]);
|
||||
}
|
||||
if (id >= MAX_ROWS)
|
||||
{
|
||||
die("There's not that many records.");
|
||||
}
|
||||
|
||||
switch(action)
|
||||
{
|
||||
case 'c':
|
||||
Database_create(conn);
|
||||
Database_write(conn);
|
||||
break;
|
||||
|
||||
case 'g':
|
||||
if (argc != 4)
|
||||
{
|
||||
die("Need an id to get");
|
||||
}
|
||||
|
||||
Database_get(conn, id);
|
||||
break;
|
||||
|
||||
case 's':
|
||||
if (argc != 6)
|
||||
{
|
||||
die("Need id, name, email to set");
|
||||
}
|
||||
|
||||
Database_set(conn, id, argv[4], argv[5]);
|
||||
Database_write(conn);
|
||||
break;
|
||||
|
||||
case 'd':
|
||||
if (argc != 4)
|
||||
{
|
||||
die("Need id to delete");
|
||||
}
|
||||
|
||||
Database_delete(conn, id);
|
||||
Database_write(conn);
|
||||
break;
|
||||
|
||||
case 'l':
|
||||
Database_list(conn);
|
||||
break;
|
||||
|
||||
default:
|
||||
die("Invalid action: c=create, g=get, s=set, l=list");
|
||||
}
|
||||
|
||||
Database_close(conn);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
CFLAGS=-g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG $(OPTFLAGS)
|
||||
LIBS=-ldl $(OPTLIBS)
|
||||
PREFIX?=/usr/local
|
||||
|
||||
SOURCES=$(wildcard src/**/*.c src/*.c)
|
||||
HEADERS=$(wildcard src/**/*.h src/*.h)
|
||||
OBJECTS=$(patsubst %.c,%.o,$(SOURCES))
|
||||
|
||||
TEST_SRC=$(wildcard tests/*_tests.c)
|
||||
TESTS=$(patsubst %.c,%,$(TEST_SRC))
|
||||
|
||||
TARGET=build/liblcthw.a
|
||||
SO_TARGET=$(patsubst %.a,%.so,$(TARGET))
|
||||
|
||||
# The Target Build
|
||||
all: $(TARGET) $(SO_TARGET) tests
|
||||
|
||||
dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS)
|
||||
dev: all
|
||||
|
||||
$(TESTS): $(TARGET) $(SO_TARGET)
|
||||
|
||||
$(TARGET): CFLAGS += -fPIC
|
||||
$(TARGET): build $(OBJECTS)
|
||||
ar rcs $@ $(OBJECTS)
|
||||
ranlib $@
|
||||
$(SO_TARGET): $(TARGET) $(OBJECTS)
|
||||
$(CC) -shared -o $@ $(OBJECTS)
|
||||
|
||||
build:
|
||||
@mkdir -p build
|
||||
@mkdir -p bin
|
||||
|
||||
# The Unit Tests
|
||||
.PHONY: tests
|
||||
tests: CFLAGS += $(TARGET)
|
||||
tests: $(TESTS)
|
||||
sh ./tests/runtests.sh
|
||||
|
||||
# The Cleaner
|
||||
clean:
|
||||
rm -rf build $(OBJECTS) $(TESTS)
|
||||
rm -f tests/tests.log
|
||||
find . -name "*.gc*" -exec rm {} \;
|
||||
rm -rf 'find . -name "*.dSYM" -print'
|
||||
|
||||
# The Install
|
||||
install: all
|
||||
install -d $(DESTDIR)/$(PREFIX)/lib/
|
||||
indtall $(TARGET) $(DESTDIR)/$(PREFIX)/lib/
|
||||
|
||||
# The Checker
|
||||
check:
|
||||
@echo Files with potentially dangerous functions.
|
||||
@egrep '[^_.>a-zA-Z0-9](str(n?cpy|n?cat|xfrm|n?dup|str|pbrk|tok|_)|stpn?cpy|a?sn?printf|byte_)' $(SOURCES) || true
|
Binary file not shown.
Binary file not shown.
|
@ -0,0 +1,37 @@
|
|||
#ifndef __dbg_h__
|
||||
#define __dbg_h__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef NDEBUG
|
||||
#define ZED_DEBUG_MACRO(M, ...)
|
||||
#else // 打印文件名,行号
|
||||
#define ZED_DEBUG_MACRO(M, ...) fprintf(stderr, "DEBUG %s:%d: " M "\n", __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#define ZED_CLEAN_ERRNO_MACRO() (errno == 0 ? "None" : strerror(errno))
|
||||
|
||||
// 打印错误的提示信息
|
||||
#define ZED_LOG_ERR_MACRO(M, ...) fprintf(stderr, "[ERROR] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, ZED_CLEAN_ERRNO_MACRO(), ##__VA_ARGS__)
|
||||
|
||||
// 打印警告的提示信息
|
||||
#define ZED_LOG_WARN_MACRO(M, ...) fprintf(stderr, "[WARN] (%s:%d: errno: %s) " M "\n", __FILE__, __LINE__, ZED_CLEAN_ERRNO_MACRO(), ##__VA_ARGS__)
|
||||
|
||||
// 打印提示信息
|
||||
#define ZED_LOG_INFO_MACRO(M, ...) fprintf(stderr, "[INFO] (%s:%s:%d) " M "\n", __FUNCTION__, __FILE__, __LINE__, ##__VA_ARGS__)
|
||||
|
||||
// 如果A为假,则打印错误提示
|
||||
#define ZED_CHECK_MACRO(A, M, ...) if(!(A)) {ZED_LOG_ERR_MACRO(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
// 根据输入参数判断运行是否成功
|
||||
#define ZED_SENTINEL_MACRO(M, ...) {ZED_LOG_ERR_MACRO(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
// 判断内存分配是否成功
|
||||
#define ZED_CHECK_MEM_MACRO(A) ZED_CHECK_MACRO((A), "Out of memory.")
|
||||
|
||||
// 如果A为假,显示调试信息
|
||||
#define ZED_CHECK_DEBUG_MACRO(A, M, ...) if(!(A)) {ZED_DEBUG_MACRO(M, ##__VA_ARGS__); errno=0; goto error;}
|
||||
|
||||
#endif
|
|
@ -0,0 +1,261 @@
|
|||
#include "lcthw/list.h"
|
||||
#include "lcthw/dbg.h"
|
||||
|
||||
List *List_create()
|
||||
{
|
||||
return calloc(1, sizeof(List));
|
||||
}
|
||||
|
||||
void List_destroy(List *list)
|
||||
{
|
||||
ZED_CHECK_MACRO(list != NULL, "list is NULL!");
|
||||
|
||||
ZED_LIST_FOREACH_MACRO(list, first, next, cur) {
|
||||
if (cur -> prev) {
|
||||
free(cur->prev);
|
||||
}
|
||||
}
|
||||
|
||||
free(list->last);
|
||||
free(list);
|
||||
|
||||
error:
|
||||
return;
|
||||
}
|
||||
|
||||
void List_clear(List *list)
|
||||
{
|
||||
ZED_CHECK_MACRO(list != NULL, "list is NULL!");
|
||||
|
||||
ZED_LIST_FOREACH_MACRO(list, first, next, cur) {
|
||||
cur->value = NULL;
|
||||
}
|
||||
|
||||
error:
|
||||
return;
|
||||
}
|
||||
|
||||
void List_clear_destroy(List *list)
|
||||
{
|
||||
List_clear(list);
|
||||
List_destroy(list);
|
||||
}
|
||||
|
||||
void List_push(List *list, char *value)
|
||||
{
|
||||
// puts("hello");
|
||||
|
||||
ListNode *node = calloc(1, sizeof(ListNode));
|
||||
ZED_CHECK_MEM_MACRO(node);
|
||||
|
||||
node->value = value;
|
||||
|
||||
if (NULL == list->last) {
|
||||
list->first = node;
|
||||
list->last = node;
|
||||
} else {
|
||||
list->last->next = node;
|
||||
node->prev = list->last;
|
||||
list->last = node;
|
||||
}
|
||||
|
||||
++(list->count);
|
||||
|
||||
error:
|
||||
return;
|
||||
}
|
||||
|
||||
char *List_pop(List *list)
|
||||
{
|
||||
ZED_CHECK_MACRO(list != NULL, "list is NULL!");
|
||||
|
||||
ListNode *node = list->last;
|
||||
|
||||
return node != NULL ? List_remove(list, node) : NULL;
|
||||
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void List_unshift(List *list, char *value)
|
||||
{
|
||||
ListNode *node = calloc(1, sizeof(ListNode));
|
||||
|
||||
ZED_CHECK_MEM_MACRO(node);
|
||||
|
||||
node -> value = value;
|
||||
|
||||
if (NULL == list->first) {
|
||||
list->first = node;
|
||||
list->last = node;
|
||||
} else {
|
||||
node->next = list->first;
|
||||
list->first->prev = node;
|
||||
list->first = node;
|
||||
}
|
||||
|
||||
++(list->count);
|
||||
|
||||
error:
|
||||
return;
|
||||
}
|
||||
|
||||
char *List_shift(List *list)
|
||||
{
|
||||
ZED_CHECK_MACRO(list != NULL, "list is NULL!");
|
||||
|
||||
ListNode *node = list->first;
|
||||
|
||||
return node != NULL ? List_remove(list, node) : NULL;
|
||||
|
||||
error:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *List_remove(List *list, ListNode *node)
|
||||
{
|
||||
void *result = NULL;
|
||||
|
||||
ZED_CHECK_MACRO(list != NULL, "list is NULL!");
|
||||
|
||||
ZED_CHECK_MACRO(list->first && list->last, "List is empty.");
|
||||
ZED_CHECK_MACRO(node, "node can't be NULL");
|
||||
|
||||
if (node == list->first && node == list->last) {
|
||||
list->first = NULL;
|
||||
list->last = NULL;
|
||||
} else if (node == list->first) {
|
||||
list->first = node->next;
|
||||
ZED_CHECK_MACRO(list->first != NULL, "Invalid list, somehow got a first that is NULL.");
|
||||
list->first->prev = NULL;
|
||||
} else if (node == list->last) {
|
||||
list->last = node->prev;
|
||||
ZED_CHECK_MACRO(list->last != NULL, "Invalid list, somehow got a next that is NULL.");
|
||||
list->last->next = NULL;
|
||||
} else {
|
||||
ListNode *after = node->next;
|
||||
ListNode *before = node->prev;
|
||||
|
||||
after->prev = before;
|
||||
before->next = after;
|
||||
}
|
||||
|
||||
--(list->count);
|
||||
result = node->value;
|
||||
free(node);
|
||||
|
||||
error:
|
||||
return result;
|
||||
}
|
||||
|
||||
List *List_copy(List *list)
|
||||
{
|
||||
List *list_copy = NULL;
|
||||
ListNode *cur = NULL;
|
||||
|
||||
if (NULL == list)
|
||||
{
|
||||
return list;
|
||||
}
|
||||
else
|
||||
{
|
||||
cur = list->first;
|
||||
list_copy = List_create();
|
||||
ZED_CHECK_MACRO(list != NULL, "Failed to create list.");
|
||||
|
||||
// 循环复制
|
||||
while (cur != NULL)
|
||||
{
|
||||
List_push(list_copy, cur -> value);
|
||||
cur = cur -> next;
|
||||
}
|
||||
}
|
||||
|
||||
error:
|
||||
|
||||
return list_copy;
|
||||
}
|
||||
|
||||
// 将递增有序的双链表lista和listb合并成一个递增有序的双链表listc
|
||||
// 处理完后,lista和listb将被销毁
|
||||
List *List_merge(List* lista, List* listb)
|
||||
{
|
||||
List *listc = NULL;
|
||||
char* value = NULL;
|
||||
|
||||
|
||||
ZED_CHECK_MACRO(lista != NULL && listb != NULL, "one or both of the lists are NULL");
|
||||
ZED_CHECK_MACRO(ZED_LIST_COUNT_MACRO(lista) != 0 && ZED_LIST_COUNT_MACRO(listb) != 0, "one or both of the lists don't have a node");
|
||||
|
||||
listc = List_create();
|
||||
|
||||
// 当两个表中均未处理完时,将值较小的结点插入到新表listc中
|
||||
while ((ZED_LIST_COUNT_MACRO(lista) > 0) && (ZED_LIST_COUNT_MACRO(listb) > 0))
|
||||
{
|
||||
if (ZED_LIST_FIRST_MACRO(lista) <= ZED_LIST_FIRST_MACRO(listb))
|
||||
{
|
||||
value = List_shift(lista);
|
||||
List_push(listc, value);
|
||||
}
|
||||
else
|
||||
{
|
||||
value = List_shift(listb);
|
||||
List_push(listc, value);
|
||||
}
|
||||
}
|
||||
|
||||
// 若表lista未完
|
||||
while (ZED_LIST_COUNT_MACRO(lista) > 0)
|
||||
{
|
||||
value = List_shift(lista);
|
||||
List_push(listc, value);
|
||||
}
|
||||
|
||||
// 若表listb未完
|
||||
while (ZED_LIST_COUNT_MACRO(listb) > 0)
|
||||
{
|
||||
value = List_shift(listb);
|
||||
List_push(listc, value);
|
||||
}
|
||||
|
||||
// 记得在主函数处销毁
|
||||
// List_clear_destroy(lista);
|
||||
// List_clear_destroy(listb);
|
||||
|
||||
error:
|
||||
return listc;
|
||||
}
|
||||
|
||||
List *List_split(List *list)
|
||||
{
|
||||
List *list_front = NULL;
|
||||
int node_count = 0;
|
||||
int i = 0;
|
||||
char *value;
|
||||
|
||||
ZED_CHECK_MACRO(list != NULL, "list is NULL");
|
||||
ZED_CHECK_MACRO(ZED_LIST_COUNT_MACRO(list) > 1, "list length <=1");
|
||||
node_count = ZED_LIST_COUNT_MACRO(list);
|
||||
list_front = List_create();
|
||||
|
||||
if (0 != node_count%2)
|
||||
{
|
||||
++node_count;
|
||||
}
|
||||
|
||||
while (i < node_count/2)
|
||||
{
|
||||
value = List_shift(list);
|
||||
List_push(list_front, value);
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
error:
|
||||
return list_front;
|
||||
}
|
||||
|
||||
int List_count(List *list)
|
||||
{
|
||||
return list -> count;
|
||||
}
|
|
@ -0,0 +1,69 @@
|
|||
#ifndef lcthw_List_h
|
||||
#define lcthw_List_h
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
// struct ListNode;
|
||||
// 双链表结点结构体,包含指向前后结点和所存储元素的指针
|
||||
typedef struct ListNode {
|
||||
struct ListNode *next;
|
||||
struct ListNode *prev;
|
||||
char *value;
|
||||
} ListNode;
|
||||
|
||||
// 双链表结构体,包含结点个数,指向第一个结点和最后一个结点的指针
|
||||
typedef struct List {
|
||||
int count;
|
||||
ListNode *first;
|
||||
ListNode *last;
|
||||
} List;
|
||||
|
||||
// 创建空的双链表
|
||||
List *List_create();
|
||||
// 销毁双链表
|
||||
void List_destroy(List *list);
|
||||
// 释放结点的值,而非结点本身。
|
||||
void List_clear(List *list);
|
||||
// 销毁双链表
|
||||
void List_clear_destroy(List *list);
|
||||
|
||||
// 获取链表结点个数
|
||||
#define ZED_LIST_COUNT_MACRO(A) ((A)->count)
|
||||
int List_count(List *list);
|
||||
|
||||
// 获取链表第一个结点所存储的值
|
||||
#define ZED_LIST_FIRST_MACRO(A) ((A)->first != NULL ? (A)->first->value : NULL)
|
||||
// 获取链表最后一个结点所存储的值
|
||||
#define ZED_LIST_LAST_MACRO(A) ((A)->last != NULL ? (A)->last->value : NULL)
|
||||
|
||||
// 在链表的结尾添加一个新元素
|
||||
void List_push(List *list, char *value);
|
||||
// 删除表中最后一个元素,并返回最后一个元素的值
|
||||
char *List_pop(List *list);
|
||||
|
||||
// 在链表的前面添加一个新元素
|
||||
void List_unshift(List *list, char *value);
|
||||
// 与List_pop一样,删除表中最后一个元素,并返回它的值
|
||||
char *List_shift(List *list);
|
||||
// 删除node结点
|
||||
char *List_remove(List *list, ListNode *node);
|
||||
|
||||
// 遍历双链表
|
||||
#define ZED_LIST_FOREACH_MACRO(LIST, FIRST, NEXT, CUR)\
|
||||
ListNode *CUR = NULL;\
|
||||
for(CUR = LIST->FIRST; CUR != NULL; CUR = CUR -> NEXT)
|
||||
|
||||
|
||||
// 复制双链表
|
||||
List *List_copy(List *list);
|
||||
|
||||
// 将递增有序的双链表lista和listb合并成一个递增有序的双链表listc
|
||||
List *List_merge(List *lista, List *listb);
|
||||
|
||||
// 从中间n/2或(n+1)/2位置处将list一分为二
|
||||
// 输入:待分割双链表list
|
||||
// 输出:分割后的链表,前半部分通过返回值返回,后半部分保留在输入的双链表list中。
|
||||
List *List_split(List *list);
|
||||
|
||||
|
||||
#endif
|
Binary file not shown.
|
@ -0,0 +1,53 @@
|
|||
#include "lcthw/list_algos.h"
|
||||
#include "lcthw/dbg.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
int List_bubble_sort(List *list, List_compare cmp)
|
||||
{
|
||||
ListNode *p = NULL; // 工作指针,指向前一个结点
|
||||
ListNode *q = NULL; // 工作指针,指向后一个结点
|
||||
int flag = 0;
|
||||
char *tmp = NULL;
|
||||
ListNode *end = NULL; // 交换终止位置
|
||||
|
||||
ZED_CHECK_MACRO(NULL != list, "list is null");
|
||||
ZED_CHECK_MACRO(ZED_LIST_COUNT_MACRO(list) > 1, "list length is less than 2");
|
||||
|
||||
p = list -> first;
|
||||
q = list -> first -> next;
|
||||
end = list -> last;
|
||||
|
||||
while (list -> first != end -> prev)
|
||||
{
|
||||
// 一趟交换
|
||||
while (q != end -> next)
|
||||
{
|
||||
flag = strcmp(p -> value, q -> value);
|
||||
if (flag > 0)
|
||||
{
|
||||
// 交换两个结点的值,先删除前一个结点,再将前一个结点插入到后一个结点之后
|
||||
tmp = p -> value;
|
||||
p -> value = q -> value;
|
||||
q -> value = tmp;
|
||||
}
|
||||
p = q;
|
||||
q = q -> next;
|
||||
|
||||
}
|
||||
end = end -> prev;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
error:
|
||||
return -1;
|
||||
}
|
||||
|
||||
List *List_merge_sort(List *list, List_compare cmp)
|
||||
{
|
||||
return list;
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,14 @@
|
|||
#ifndef lcthw_List_algos_h
|
||||
#define lcthw_List_algos_h
|
||||
|
||||
#include <lcthw/list.h>
|
||||
|
||||
typedef int (*List_compare) (const void *a, const void *b);
|
||||
|
||||
// 冒泡排序
|
||||
int List_bubble_sort(List *list, List_compare cmp);
|
||||
|
||||
// 归并排序
|
||||
List *List_merge_sort(List *list, List_compare cmp);
|
||||
|
||||
#endif
|
Binary file not shown.
|
@ -0,0 +1,95 @@
|
|||
!_TAG_FILE_FORMAT 2 /extended format; --format=1 will not append ;" to lines/
|
||||
!_TAG_FILE_SORTED 1 /0=unsorted, 1=sorted, 2=foldcase/
|
||||
!_TAG_OUTPUT_EXCMD mixed /number, pattern, mixed, or combineV2/
|
||||
!_TAG_OUTPUT_FILESEP slash /slash or backslash/
|
||||
!_TAG_OUTPUT_MODE u-ctags /u-ctags or e-ctags/
|
||||
!_TAG_PATTERN_LENGTH_LIMIT 96 /0 for no limit/
|
||||
!_TAG_PROC_CWD /home/boyang/文档/Project/C/lcthw/lcthw-ex33/liblcthw/ //
|
||||
!_TAG_PROGRAM_AUTHOR Universal Ctags Team //
|
||||
!_TAG_PROGRAM_NAME Universal Ctags /Derived from Exuberant Ctags/
|
||||
!_TAG_PROGRAM_URL https://ctags.io/ /official site/
|
||||
!_TAG_PROGRAM_VERSION 5.9.0 //
|
||||
$(SO_TARGET) Makefile /^$(SO_TARGET): $(TARGET) $(OBJECTS)$/;" t
|
||||
$(TARGET) Makefile /^$(TARGET): CFLAGS += -fPIC$/;" t
|
||||
$(TARGET) Makefile /^$(TARGET): build $(OBJECTS)$/;" t
|
||||
$(TESTS) Makefile /^$(TESTS): $(TARGET) $(SO_TARGET)$/;" t
|
||||
CFLAGS Makefile /^CFLAGS=-g -O2 -Wall -Wextra -Isrc -rdynamic -DNDEBUG $(OPTFLAGS)$/;" m
|
||||
CFLAGS Makefile /^dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS)$/;" m
|
||||
HEADERS Makefile /^HEADERS=$(wildcard src\/**\/*.h src\/*.h)$/;" m
|
||||
LIBS Makefile /^LIBS=-ldl $(OPTLIBS)$/;" m
|
||||
List src/lcthw/list_algos.h /^typedef struct List {$/;" s
|
||||
List src/lcthw/list_algos.h /^} List;$/;" t typeref:struct:List
|
||||
ListNode src/lcthw/list_algos.h /^typedef struct ListNode {$/;" s
|
||||
ListNode src/lcthw/list_algos.h /^} ListNode;$/;" t typeref:struct:ListNode
|
||||
List_bubble_sort src/lcthw/list.c /^int List_bubble_sort(List *list, List_compare cmp)$/;" f typeref:typename:int
|
||||
List_clear src/lcthw/list.c /^void List_clear(List *list)$/;" f typeref:typename:void
|
||||
List_clear_destroy src/lcthw/list.c /^void List_clear_destroy(List *list)$/;" f typeref:typename:void
|
||||
List_compare src/lcthw/list_algos.h /^typedef int (*List_compare) (const void *a, const void *b);$/;" t typeref:typename:int (*)(const void * a,const void * b)
|
||||
List_copy src/lcthw/list.c /^List *List_copy(List *list)$/;" f typeref:typename:List *
|
||||
List_create src/lcthw/list.c /^List *List_create()$/;" f typeref:typename:List *
|
||||
List_destroy src/lcthw/list.c /^void List_destroy(List *list)$/;" f typeref:typename:void
|
||||
List_merge src/lcthw/list.c /^List *List_merge(List* lista, List* listb)$/;" f typeref:typename:List *
|
||||
List_merge_sort src/lcthw/list.c /^List *List_merge_sort(List *list, List_compare cmp)$/;" f typeref:typename:List *
|
||||
List_pop src/lcthw/list.c /^char *List_pop(List *list)$/;" f typeref:typename:char *
|
||||
List_push src/lcthw/list.c /^void List_push(List *list, char *value)$/;" f typeref:typename:void
|
||||
List_remove src/lcthw/list.c /^char *List_remove(List *list, ListNode *node)$/;" f typeref:typename:char *
|
||||
List_shift src/lcthw/list.c /^char *List_shift(List *list)$/;" f typeref:typename:char *
|
||||
List_split src/lcthw/list.c /^List *List_split(List *list)$/;" f typeref:typename:List *
|
||||
List_unshift src/lcthw/list.c /^void List_unshift(List *list, char *value)$/;" f typeref:typename:void
|
||||
NUM_VALUES tests/list_algos_tests.c /^#define NUM_VALUES /;" d file:
|
||||
OBJECTS Makefile /^OBJECTS=$(patsubst %.c,%.o,$(SOURCES))$/;" m
|
||||
PREFIX Makefile /^PREFIX?=\/usr\/local$/;" m
|
||||
SOURCES Makefile /^SOURCES=$(wildcard src\/**\/*.c src\/*.c)$/;" m
|
||||
SO_TARGET Makefile /^SO_TARGET=$(patsubst %.a,%.so,$(TARGET))$/;" m
|
||||
TARGET Makefile /^TARGET=build\/liblcthw.a$/;" m
|
||||
TESTS Makefile /^TESTS=$(patsubst %.c,%,$(TEST_SRC))$/;" m
|
||||
TEST_SRC Makefile /^TEST_SRC=$(wildcard tests\/*_tests.c)$/;" m
|
||||
ZED_CHECK_DEBUG_MACRO src/lcthw/dbg.h /^#define ZED_CHECK_DEBUG_MACRO(/;" d
|
||||
ZED_CHECK_MACRO src/lcthw/dbg.h /^#define ZED_CHECK_MACRO(/;" d
|
||||
ZED_CHECK_MEM_MACRO src/lcthw/dbg.h /^#define ZED_CHECK_MEM_MACRO(/;" d
|
||||
ZED_CLEAN_ERRNO_MACRO src/lcthw/dbg.h /^#define ZED_CLEAN_ERRNO_MACRO(/;" d
|
||||
ZED_DEBUG_MACRO src/lcthw/dbg.h /^#define ZED_DEBUG_MACRO(/;" d
|
||||
ZED_LIST_COUNT_MACRO src/lcthw/list_algos.h /^#define ZED_LIST_COUNT_MACRO(/;" d
|
||||
ZED_LIST_FIRST_MACRO src/lcthw/list_algos.h /^#define ZED_LIST_FIRST_MACRO(/;" d
|
||||
ZED_LIST_FOREACH_MACRO src/lcthw/list_algos.h /^#define ZED_LIST_FOREACH_MACRO(/;" d
|
||||
ZED_LIST_LAST_MACRO src/lcthw/list_algos.h /^#define ZED_LIST_LAST_MACRO(/;" d
|
||||
ZED_LOG_ERR_MACRO src/lcthw/dbg.h /^#define ZED_LOG_ERR_MACRO(/;" d
|
||||
ZED_LOG_INFO_MACRO src/lcthw/dbg.h /^#define ZED_LOG_INFO_MACRO(/;" d
|
||||
ZED_LOG_WARN_MACRO src/lcthw/dbg.h /^#define ZED_LOG_WARN_MACRO(/;" d
|
||||
ZED_MU_ASSERT_MACRO tests/minunit.h /^#define ZED_MU_ASSERT_MACRO(/;" d
|
||||
ZED_MU_RUN_TEST_MACRO tests/minunit.h /^#define ZED_MU_RUN_TEST_MACRO(/;" d
|
||||
ZED_MU_SUITE_START_MACRO tests/minunit.h /^#define ZED_MU_SUITE_START_MACRO(/;" d
|
||||
ZED_RUN_TESTS_MACRO tests/minunit.h /^#define ZED_RUN_TESTS_MACRO(/;" d
|
||||
ZED_SENTINEL_MACRO src/lcthw/dbg.h /^#define ZED_SENTINEL_MACRO(/;" d
|
||||
__dbg_h__ src/lcthw/dbg.h /^#define __dbg_h__$/;" d
|
||||
_minunit_h tests/minunit.h /^#define _minunit_h$/;" d
|
||||
all Makefile /^all: $(TARGET) $(SO_TARGET) tests$/;" t
|
||||
all_tests tests/list_algos_tests.c /^char *all_tests()$/;" f typeref:typename:char *
|
||||
all_tests tests/list_tests.c /^char *all_tests()$/;" f typeref:typename:char *
|
||||
build Makefile /^build:$/;" t
|
||||
check Makefile /^check:$/;" t
|
||||
clean Makefile /^clean:$/;" t
|
||||
count src/lcthw/list_algos.h /^ int count;$/;" m struct:List typeref:typename:int
|
||||
create_words tests/list_algos_tests.c /^List *create_words()$/;" f typeref:typename:List *
|
||||
dev Makefile /^dev: CFLAGS=-g -Wall -Isrc -Wall -Wextra $(OPTFLAGS)$/;" t
|
||||
dev Makefile /^dev: all$/;" t
|
||||
first src/lcthw/list_algos.h /^ ListNode *first;$/;" m struct:List typeref:typename:ListNode *
|
||||
install Makefile /^install: all$/;" t
|
||||
is_sorted tests/list_algos_tests.c /^int is_sorted(List *words)$/;" f typeref:typename:int
|
||||
last src/lcthw/list_algos.h /^ ListNode *last;$/;" m struct:List typeref:typename:ListNode *
|
||||
lcthw_List_h src/lcthw/list_algos.h /^#define lcthw_List_h$/;" d
|
||||
next src/lcthw/list_algos.h /^ struct ListNode *next;$/;" m struct:ListNode typeref:struct:ListNode *
|
||||
prev src/lcthw/list_algos.h /^ struct ListNode *prev;$/;" m struct:ListNode typeref:struct:ListNode *
|
||||
test_bubble_sort tests/list_algos_tests.c /^char *test_bubble_sort()$/;" f typeref:typename:char *
|
||||
test_create_destroy tests/list_tests.c /^char *test_create_destroy()$/;" f typeref:typename:char *
|
||||
test_merge tests/list_tests.c /^char *test_merge()$/;" f typeref:typename:char *
|
||||
test_merge_sort tests/list_algos_tests.c /^char *test_merge_sort()$/;" f typeref:typename:char *
|
||||
test_push_copy tests/list_tests.c /^char *test_push_copy()$/;" f typeref:typename:char *
|
||||
test_push_pop1 tests/list_tests.c /^char *test_push_pop1()$/;" f typeref:typename:char *
|
||||
test_split tests/list_tests.c /^char *test_split()$/;" f typeref:typename:char *
|
||||
test_unshift_remove_shift tests/list_tests.c /^char *test_unshift_remove_shift()$/;" f typeref:typename:char *
|
||||
tests Makefile /^tests: $(TESTS)$/;" t
|
||||
tests Makefile /^tests: CFLAGS += $(TARGET)$/;" t
|
||||
tests_run_globel tests/minunit.h /^int tests_run_globel = 0;$/;" v typeref:typename:int
|
||||
value src/lcthw/list_algos.h /^ char *value;$/;" m struct:ListNode typeref:typename:char *
|
||||
values tests/list_algos_tests.c /^char *values[] = {"XXXX", "1234", "abcd", "xjvef", "NDSS"};$/;" v typeref:typename:char * []
|
Binary file not shown.
|
@ -0,0 +1,84 @@
|
|||
#include "minunit.h"
|
||||
#include "lcthw/list_algos.h"
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#define NUM_VALUES 5
|
||||
|
||||
char *values[] = {"XXXX", "1234", "abcd", "xjvef", "NDSS"};
|
||||
|
||||
List *create_words()
|
||||
{
|
||||
int i = 0;
|
||||
List *words = List_create();
|
||||
|
||||
for (i = 0; i < NUM_VALUES; ++i)
|
||||
{
|
||||
List_push(words, values[i]);
|
||||
}
|
||||
|
||||
return words;
|
||||
}
|
||||
|
||||
int is_sorted(List *words)
|
||||
{
|
||||
ZED_LIST_FOREACH_MACRO(words, first, next, cur) {
|
||||
if (cur -> next && strcmp(cur -> value, cur -> next -> value) > 0) {
|
||||
ZED_DEBUG_MACRO("%s %s", (char *)cur -> value, (char *)cur -> next -> value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
char *test_bubble_sort()
|
||||
{
|
||||
List *words = create_words();
|
||||
|
||||
// should work on a list that needs sorting
|
||||
int rc = List_bubble_sort(words, (List_compare)strcmp);
|
||||
|
||||
ZED_MU_ASSERT_MACRO(rc != 0, "Bubble sort failed.");
|
||||
ZED_MU_ASSERT_MACRO(is_sorted(words), "Words are not sorted after bubble sort.");
|
||||
|
||||
// should work on an already sorted list
|
||||
rc = List_bubble_sort(words, (List_compare)strcmp);
|
||||
ZED_MU_ASSERT_MACRO(0 != rc, "Bubble sort of already sorted failed.");
|
||||
ZED_MU_ASSERT_MACRO(is_sorted(words), "Words should be sort if already bubble sorted.");
|
||||
|
||||
List_clear_destroy(words);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *test_merge_sort()
|
||||
{
|
||||
List *words = create_words();
|
||||
|
||||
// should work on a list that needs sorting
|
||||
List *res = List_merge_sort(words, (List_compare)strcmp);
|
||||
ZED_MU_ASSERT_MACRO(is_sorted(res), "Words are not sorted after merge sort.");
|
||||
|
||||
List *res2 = List_merge_sort(res, (List_compare) strcmp);
|
||||
ZED_MU_ASSERT_MACRO(is_sorted(res), "Should still be sorted after merge sort.");
|
||||
List_destroy(res2);
|
||||
List_destroy(res);
|
||||
|
||||
List_destroy(words);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *all_tests()
|
||||
{
|
||||
ZED_MU_SUITE_START_MACRO();
|
||||
|
||||
ZED_MU_RUN_TEST_MACRO(test_bubble_sort);
|
||||
ZED_MU_RUN_TEST_MACRO(test_merge_sort);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ZED_RUN_TESTS_MACRO(all_tests);
|
Binary file not shown.
|
@ -0,0 +1,278 @@
|
|||
#include "minunit.h"
|
||||
#include "lcthw/list_algos.h"
|
||||
#include <assert.h>
|
||||
|
||||
|
||||
char *test_create_destroy()
|
||||
{
|
||||
// test create
|
||||
List *list = List_create();
|
||||
|
||||
ZED_MU_ASSERT_MACRO(NULL == list, "Failed to create list_globel.");
|
||||
// test destroy
|
||||
List_clear_destroy(list);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *test_push_pop1()
|
||||
{
|
||||
// test create
|
||||
List *list = List_create();
|
||||
char *test1 = "test1 data";
|
||||
char *test2 = "test2 data";
|
||||
char *test3 = "test3 data";
|
||||
char *test4 = "test4 data";
|
||||
|
||||
ZED_MU_ASSERT_MACRO(NULL == list, "Failed to create list_globel.");
|
||||
|
||||
// test push
|
||||
ZED_MU_ASSERT_MACRO(list->count<0, "invalid list");
|
||||
ZED_MU_ASSERT_MACRO(list->count>0&&(NULL == ZED_LIST_FIRST_MACRO(list)), "invalid list");
|
||||
|
||||
List_push(list, test1);
|
||||
ZED_MU_ASSERT_MACRO(test1 != ZED_LIST_LAST_MACRO(list), "Wrong last values.");
|
||||
|
||||
List_push(list, test2);
|
||||
ZED_MU_ASSERT_MACRO(test2 != ZED_LIST_LAST_MACRO(list), "Wrong last values.");
|
||||
|
||||
List_push(list, test3);
|
||||
ZED_MU_ASSERT_MACRO(test3 != ZED_LIST_LAST_MACRO(list), "Wrong last values.");
|
||||
ZED_MU_ASSERT_MACRO(3 != ZED_LIST_COUNT_MACRO(list), "Wrong count on push.");
|
||||
|
||||
List_push(list, test4);
|
||||
ZED_MU_ASSERT_MACRO(test4 != ZED_LIST_LAST_MACRO(list), "Wrong last values.");
|
||||
|
||||
// test pop
|
||||
char *val = List_pop(list);
|
||||
|
||||
ZED_MU_ASSERT_MACRO(test4 != val, "Wrong value on pop.");
|
||||
|
||||
val = List_pop(list);
|
||||
ZED_MU_ASSERT_MACRO(test3 != val, "Wrong value on pop.");
|
||||
|
||||
val = List_pop(list);
|
||||
ZED_MU_ASSERT_MACRO(test2 != val, "Wrong value on pop.");
|
||||
|
||||
val = List_pop(list);
|
||||
ZED_MU_ASSERT_MACRO(test1 != val, "Wrong value on pop.");
|
||||
ZED_MU_ASSERT_MACRO(0 != ZED_LIST_COUNT_MACRO(list), "Wrong count after pop.");
|
||||
|
||||
// test destroy
|
||||
List_clear_destroy(list);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *test_unshift_remove_shift()
|
||||
{
|
||||
// test create
|
||||
List *list = List_create();
|
||||
char *test1 = "test1 data";
|
||||
char *test2 = "test2 data";
|
||||
char *test3 = "test3 data";
|
||||
|
||||
ZED_MU_ASSERT_MACRO(NULL == list, "Failed to create list_globel.");
|
||||
|
||||
// test unshift
|
||||
List_unshift(list, test1);
|
||||
ZED_MU_ASSERT_MACRO(test1 != ZED_LIST_FIRST_MACRO(list), "Wrong first value.");
|
||||
|
||||
List_unshift(list, test2);
|
||||
ZED_MU_ASSERT_MACRO(test2 != ZED_LIST_FIRST_MACRO(list), "Wrong first value.");
|
||||
|
||||
List_unshift(list, test3);
|
||||
ZED_MU_ASSERT_MACRO(test3 != ZED_LIST_FIRST_MACRO(list), "Wrong first value.");
|
||||
ZED_MU_ASSERT_MACRO(3 != ZED_LIST_COUNT_MACRO(list), "Wrong count on unshift.");
|
||||
|
||||
// we only need to test the middle remove case since push/shift
|
||||
// already tests the other cases
|
||||
// test remove
|
||||
char *val = List_remove(list, list->first->next);
|
||||
|
||||
ZED_MU_ASSERT_MACRO(test2 != val, "Wrong removed element.");
|
||||
ZED_MU_ASSERT_MACRO(2 != ZED_LIST_COUNT_MACRO(list), "Wrong count after remove.");
|
||||
ZED_MU_ASSERT_MACRO(test3 != ZED_LIST_FIRST_MACRO(list), "Wrong first after remove.");
|
||||
ZED_MU_ASSERT_MACRO(test1 != ZED_LIST_LAST_MACRO(list), "Wrong last after remove.");
|
||||
|
||||
// test shift
|
||||
ZED_MU_ASSERT_MACRO(0 == ZED_LIST_COUNT_MACRO(list), "Wrong count before shift.");
|
||||
|
||||
char *val1 = List_shift(list);
|
||||
|
||||
ZED_MU_ASSERT_MACRO(test3 != val1, "Wrong value on shift.");
|
||||
|
||||
val1 = List_shift(list);
|
||||
ZED_MU_ASSERT_MACRO(test1 != val1, "Wrong value on shift.");
|
||||
ZED_MU_ASSERT_MACRO(0 != ZED_LIST_COUNT_MACRO(list), "Wrong count after shift.");
|
||||
|
||||
// test destroy
|
||||
List_clear_destroy(list);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *test_push_copy()
|
||||
{
|
||||
// test create
|
||||
List *list = List_create();
|
||||
List *list_copy = NULL;
|
||||
char *test1 = "test1 data";
|
||||
char *test2 = "test2 data";
|
||||
char *test3 = "test3 data";
|
||||
|
||||
ZED_MU_ASSERT_MACRO(NULL == list, "Failed to create list.");
|
||||
|
||||
// test push
|
||||
ZED_MU_ASSERT_MACRO(list->count < 0, "invalid list");
|
||||
ZED_MU_ASSERT_MACRO((list->count > 0) && (NULL == ZED_LIST_FIRST_MACRO(list)), "invalid list");
|
||||
|
||||
List_push(list, test1);
|
||||
ZED_MU_ASSERT_MACRO(test1 != ZED_LIST_LAST_MACRO(list), "Wrong last values.");
|
||||
|
||||
List_push(list, test2);
|
||||
ZED_MU_ASSERT_MACRO(test2 != ZED_LIST_LAST_MACRO(list), "Wrong last values.");
|
||||
|
||||
List_push(list, test3);
|
||||
ZED_MU_ASSERT_MACRO(test3 != ZED_LIST_LAST_MACRO(list), "Wrong last values.");
|
||||
|
||||
// TEST LIST_COPY
|
||||
list_copy = List_copy(list);
|
||||
|
||||
char *val = List_pop(list_copy);
|
||||
|
||||
ZED_MU_ASSERT_MACRO(val != test3, "Wrong value on pop.");
|
||||
|
||||
val = List_pop(list_copy);
|
||||
ZED_MU_ASSERT_MACRO(val != test2, "Wrong value on pop.");
|
||||
|
||||
val = List_pop(list_copy);
|
||||
ZED_MU_ASSERT_MACRO(val != test1, "Wrong value on pop.");
|
||||
ZED_MU_ASSERT_MACRO(ZED_LIST_COUNT_MACRO(list_copy) != 0, "Wrong count after pop.");
|
||||
|
||||
// test destroy
|
||||
List_clear_destroy(list);
|
||||
List_clear_destroy(list_copy);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *test_merge()
|
||||
{
|
||||
List *list1 = List_create();
|
||||
List *list2 = List_create();
|
||||
List *list_merge = NULL;
|
||||
char *test1 = "test1 data";
|
||||
char *test2 = "test2 data";
|
||||
char *test3 = "test3 data";
|
||||
char *test4 = "test4 data";
|
||||
char *test5 = "test5 data";
|
||||
char *test6 = "test6 data";
|
||||
|
||||
ZED_MU_ASSERT_MACRO(NULL == list1 || NULL == list2, "Failed to create list");
|
||||
|
||||
List_push(list1, test1);
|
||||
ZED_MU_ASSERT_MACRO(test1 != ZED_LIST_LAST_MACRO(list1), "Wrong last values.");
|
||||
|
||||
List_push(list1, test3);
|
||||
ZED_MU_ASSERT_MACRO(test3 != ZED_LIST_LAST_MACRO(list1), "Wrong last values.");
|
||||
|
||||
List_push(list1, test5);
|
||||
ZED_MU_ASSERT_MACRO(test5 != ZED_LIST_LAST_MACRO(list1), "Wrong last values.");
|
||||
ZED_MU_ASSERT_MACRO(3 != ZED_LIST_COUNT_MACRO(list1), "Wrong list count.");
|
||||
|
||||
List_push(list2, test2);
|
||||
ZED_MU_ASSERT_MACRO(test2 != ZED_LIST_LAST_MACRO(list2), "Wrong last values.");
|
||||
|
||||
List_push(list2, test4);
|
||||
ZED_MU_ASSERT_MACRO(test4 != ZED_LIST_LAST_MACRO(list2), "Wrong last values.");
|
||||
|
||||
List_push(list2, test6);
|
||||
ZED_MU_ASSERT_MACRO(test6 != ZED_LIST_LAST_MACRO(list2), "Wrong last values.");
|
||||
ZED_MU_ASSERT_MACRO(3 != ZED_LIST_COUNT_MACRO(list2), "Wrong list count.");
|
||||
|
||||
list_merge = List_merge(list1, list2);
|
||||
|
||||
char* val = List_pop(list_merge);
|
||||
|
||||
// puts(val);
|
||||
ZED_MU_ASSERT_MACRO(val != test6, "Wrong value on pop.");
|
||||
|
||||
val = List_pop(list_merge);
|
||||
ZED_MU_ASSERT_MACRO(val != test5, "Wrong value on pop.");
|
||||
|
||||
val = List_pop(list_merge);
|
||||
ZED_MU_ASSERT_MACRO(val != test4, "Wrong value on pop.");
|
||||
|
||||
val = List_pop(list_merge);
|
||||
ZED_MU_ASSERT_MACRO(val != test3, "Wrong value on pop.");
|
||||
|
||||
val = List_pop(list_merge);
|
||||
ZED_MU_ASSERT_MACRO(val != test2, "Wrong value on pop.");
|
||||
|
||||
val = List_pop(list_merge);
|
||||
ZED_MU_ASSERT_MACRO(val != test1, "Wrong value on pop.");
|
||||
|
||||
ZED_MU_ASSERT_MACRO(0 != ZED_LIST_COUNT_MACRO(list_merge), "Wrong value on pop.");
|
||||
|
||||
List_clear_destroy(list_merge);
|
||||
List_clear_destroy(list1);
|
||||
List_clear_destroy(list2);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *test_split()
|
||||
{
|
||||
List *list = List_create();
|
||||
List *list_front = NULL;
|
||||
char *test1 = "test1 data";
|
||||
char *test2 = "test2 data";
|
||||
char *test3 = "test3 data";
|
||||
|
||||
ZED_MU_ASSERT_MACRO(NULL == list, "Failed to create list create");
|
||||
|
||||
List_push(list, test1);
|
||||
ZED_MU_ASSERT_MACRO(test1 != ZED_LIST_LAST_MACRO(list), "Wrong last values.");
|
||||
|
||||
List_push(list, test2);
|
||||
ZED_MU_ASSERT_MACRO(test2 != ZED_LIST_LAST_MACRO(list), "Wrong last values");
|
||||
|
||||
List_push(list, test3);
|
||||
ZED_MU_ASSERT_MACRO(test3 != ZED_LIST_LAST_MACRO(list), "Wrong last values.");
|
||||
ZED_MU_ASSERT_MACRO(3 != ZED_LIST_COUNT_MACRO(list), "Wrong list count.");
|
||||
|
||||
list_front = List_split(list);
|
||||
|
||||
char *val = List_pop(list_front);
|
||||
ZED_MU_ASSERT_MACRO(test2 != val, "Wrong value on pop.");
|
||||
|
||||
val = List_pop(list_front);
|
||||
ZED_MU_ASSERT_MACRO(test1 != val, "Wrong value on pop.");
|
||||
ZED_MU_ASSERT_MACRO(0 != ZED_LIST_COUNT_MACRO(list_front), "Wrong list count");
|
||||
|
||||
val = List_pop(list);
|
||||
ZED_MU_ASSERT_MACRO(test3 != val, "Wrong value on pop.");
|
||||
ZED_MU_ASSERT_MACRO(0 != ZED_LIST_COUNT_MACRO(list), "Wrong list count");
|
||||
|
||||
List_clear_destroy(list_front);
|
||||
List_clear_destroy(list);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
char *all_tests()
|
||||
{
|
||||
ZED_MU_SUITE_START_MACRO();
|
||||
|
||||
ZED_MU_RUN_TEST_MACRO(test_create_destroy);
|
||||
ZED_MU_RUN_TEST_MACRO(test_push_pop1);
|
||||
ZED_MU_RUN_TEST_MACRO(test_unshift_remove_shift);
|
||||
ZED_MU_RUN_TEST_MACRO(test_push_copy);
|
||||
ZED_MU_RUN_TEST_MACRO(test_merge);
|
||||
ZED_MU_RUN_TEST_MACRO(test_split);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ZED_RUN_TESTS_MACRO(all_tests);
|
|
@ -0,0 +1,37 @@
|
|||
#undef NDEBUG
|
||||
#ifndef _minunit_h
|
||||
#define _minunit_h
|
||||
|
||||
#include <stdio.h>
|
||||
#include "lcthw/dbg.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
// 设置消息为空
|
||||
#define ZED_MU_SUITE_START_MACRO() char *message = NULL
|
||||
|
||||
// 如果测试失败,显示错误信息
|
||||
#define ZED_MU_ASSERT_MACRO(test, message) if (test) {\
|
||||
ZED_LOG_ERR_MACRO(message); return message; }
|
||||
|
||||
// 运行一个测试,如果测试失败,则返回提示信息
|
||||
#define ZED_MU_RUN_TEST_MACRO(test) ZED_DEBUG_MACRO("\n-----%s", " " #test); \
|
||||
message = test(); ++tests_run_globel; if (message) return message;
|
||||
|
||||
// 测试主函数
|
||||
#define ZED_RUN_TESTS_MACRO(name) int main(int argc, char *argv[]) {\
|
||||
ZED_DEBUG_MACRO("----- RUNNING: %s", argv[0]); \
|
||||
printf("----\n%d test RUNNING: %s\n", argc, argv[0]); \
|
||||
char *result = name(); \
|
||||
if (result != 0) { \
|
||||
printf("FAILED: %s\n", result); \
|
||||
} \
|
||||
else { \
|
||||
printf("ALL TESTS PASSED\n"); \
|
||||
} \
|
||||
printf("Function tests run: %d.\n", tests_run_globel); \
|
||||
exit(result != 0); \
|
||||
}
|
||||
|
||||
int tests_run_globel = 0;
|
||||
|
||||
#endif
|
|
@ -0,0 +1,19 @@
|
|||
echo "Running unit tests:"
|
||||
|
||||
for i in tests/*_tests
|
||||
do
|
||||
if test -f $i
|
||||
then
|
||||
if $VALGRIND ./$i 2>> tests/tests.log
|
||||
then
|
||||
echo $1 PASS
|
||||
else
|
||||
echo "ERROR in test $i: here's tests/tests.log"
|
||||
echo "------"
|
||||
tail tests/tests.log
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
|
@ -0,0 +1,4 @@
|
|||
DEBUG tests/list_algos_tests.c:84: ----- RUNNING: ./tests/list_algos_tests
|
||||
DEBUG tests/list_algos_tests.c:78:
|
||||
----- test_bubble_sort
|
||||
Segmentation fault (core dumped)
|
Loading…
Reference in New Issue