学《elementary-algorithms》的PART 1需要用到,所以就自己简单实现了一下,用的是C语言,数据结构的操作也不全,只是实现了需要用到的部分。代码风格借鉴了之前学过的一个开源2D引擎-Orx Engine,前缀wtl
是字母WangTaL
的缩写,是廖望塔的意思。代码在codeblocks17下编译通过,gcc7编译不过。(2018.5.19更新-要在gcc下编译通过,加上参数“-fms-extensions”)。
list.h单链表的头文件
#ifndef _LIST_H_
#define _LIST_H_
// 单链表的节点结构,只支持存放无符号长整形数据
typedef struct _wtlNODE {
struct _wtlNODE* next;
unsigned long value;
} wtlNODE;
// 单链表结构,只有一个元素,header中的value用于记录链表的长度,next指向实际的节点
typedef struct _wtlLIST {
struct _wtlNODE* header;
} wtlLIST;
// 创建一个单链表
wtlLIST* wtlList_Create(void);
// 销毁一个单链表,注意传入的是个二级指针,而不是一级指针
void wtlList_Destroy(wtlLIST** list);
// 获取单链表中第index个节点的值,从0开始
unsigned long wtlList_GetValue(wtlLIST* list, int index);
// 获取单链表的长度,也就是节点个数
int wtlList_Length(wtlLIST* list);
// 创建一个存放value的节点
wtlNODE* wtlNode_Create(unsigned long value);
// 销毁一个节点,也是传入二级指针
void wtlNode_Destroy(wtlNODE** node);
#endif // _LIST_H_
list.c单链表的实现文件
#include <stdlib.h>
#include <assert.h>
#include "list.h"
wtlLIST* wtlList_Create(void){
wtlLIST* list = malloc(
sizeof(*list) + sizeof(wtlNODE) // 这样申请内存是为了便于一次释放
);
assert(list != NULL);
// 申请内存的时候多申请了一个wtlNODE的大小,所以让header指向这部分就行了
// 这样就不用调用wtlNode_Create()为header单独申请内存
list->header = (wtlNODE*)(list + 1);
//初始化header的内容
list->header->next = NULL;
list->header->value = 0;
return list;
}
void wtlList_Destroy(wtlLIST** list){
if (NULL == *list) {
return;
}
// 该节点指向链表中实际的节点
wtlNODE* node = (*list)->header->next;
// 如果该节点不为空
while (node != NULL) {
// 就让链表的next指向node的next,这样就不会丢失后面的节点信息
(*list)->header->next = node->next;
// 同时释放node的内存
wtlNode_Destroy(&node);
// 再将node赋值为header的next
node = (*list)->header->next;
} // 重复完整个循环后,链表的所有节点的内存就被释放了,不包括header这个特殊节点
// 最后释放list指向的内存,包括header这个特殊节点,因为是一起申请的
free(*list);
// 注意,如果不是二级指针的话,就无法改变list指向的内容,为了安全起见,让它指向空
// 就像形参传普通变量无法改变它的值一样,为了改变它的值,得传它的指针
// 为了改变指针的内容,就得传指针的指针
*list = NULL;
}
unsigned long wtlList_GetValue(wtlLIST* list, int index){
// 链表为空,返回-1
if (NULL == list) {
return -1;
}
int len = (int)(list->header->value);
wtlNODE* current = list->header->next;
// 链表不为空,但是链表不存在任何节点
if (NULL == current) {
return -1; // 这里返回-1似乎也不合理,万一链表中要存入-1这个值呢...不过也不知道返回什么值合理
}
// 如果index小于0,直接返回第一个节点的值
if (index < 0) {
return current->value;
}
for (int i = 0; i < index && i < len - 1; i++) {
current = current->next;
}
return current->value;
}
int wtlList_Length(wtlLIST* list){
return (int)(list->header->value);
}
wtlNODE* wtlNode_Create(unsigned long value){
wtlNODE* node = malloc(sizeof(*node));
assert(node != NULL);
node->next = NULL;
node->value = value;
return node;
}
void wtlNode_Destroy(wtlNODE** node){
if (*node != NULL) {
free(*node);
*node = NULL;
}
}
在单链表的基础上加上特有的操作,形成一个有序正整数集。差不多是用到了继承的思想吧。
set.h有序正整数集的头文件
#ifndef _SET_H_
#define _SET_H_
#include "list.h"
//集合的结构
typedef struct _wtlSET {
// 匿名结构体用法
// 这样做是为了使用的时候可以直接set->header,而不是set->list->header
struct _wtlLIST;
} wtlSET;
wtlSET* wtlSet_Create(void);
void wtlSet_Destroy(wtlSET** set);
// 向集合中插入一个元素,可保证集合中元素的唯一性和有序性
void wtlSet_Insert(wtlSET* set, unsigned long value);
// 获取集合的第一个元素,且会释放该节点
unsigned long wtlSet_GetFirst(wtlSET* set);
int wtlSet_Length(wtlSET* set);
#endif /* _SET_H_ */
set.c集合的实现部分
#include <stdlib.h>
#include <assert.h>
#include "set.h"
// 集合的创建,直接调用链表的创建函数,因为set的结构和list的结构是一样的
wtlSET* wtlSet_Create(void){
return (wtlSET*)wtlList_Create();
}
// 集合的销毁,道理同创建函数一样
void wtlSet_Destroy(wtlSET** set){
wtlLIST* p = (wtlLIST*)(*set);
wtlList_Destroy(&p);
}
int wtlSet_Length(wtlSET* set){
return wtlList_Length((wtlLIST*)set);
}
void wtlSet_Insert(wtlSET* set, unsigned long value){
assert(set != NULL);
// current指向header,而不是header的next
wtlNODE* current = set->header;
while (current) {
// 如果集合一个元素都不包含
if (NULL == current->next) {
// 直接将该元素作为第一个元素插入
wtlNODE* node = wtlNode_Create(value);
current->next = node;
(set->header->value)++;
// 结束循环
break;
}
// 如果集合包含元素了,就按下面的步骤插入元素
wtlNODE* next = current->next;
// 将要插入的元素已存在集合中,就不插入了
if (next->value == value) {
break;
}
// 不存在则找到合适的位置插入
if (next->value > value) {
wtlNODE* node = wtlNode_Create(value);
node->next = next;
current->next = node;
(set->header->value)++;
break;
}
current = next;
}
}
unsigned long wtlSet_GetFirst(wtlSET* set){
wtlNODE* first = set->header->next;
unsigned long value = 0;
if (NULL == first) {
return value;
}
value = first->value;
set->header->next = first->next;
(set->header->value)--;
wtlNode_Destroy(&first);
return value;
}
同样的,在单链表的基础上增加特有的操作,形成一个队列。
queue.h队列的头文件
#ifndef _QUEUE_H_
#define _QUEUE_H_
#include "list.h"
// 队列的结构
typedef struct _wtlQUEUE {
// 继承自list,该用法在set部分有讲
struct _wtlLIST;
// 增加一个tail指针用于指向尾节点,使元素的入列操作的时间复杂度达到为O(1)
wtlNODE* tail;
} wtlQUEUE;
wtlQUEUE* wtlQueue_Create(void);
void wtlQueue_Destroy(wtlQUEUE** queue);
// 元素的入列操作
void wtlQueue_Push(wtlQUEUE* queue, unsigned long value);
// 元素的出列操作
unsigned long wtlQueue_Pop(wtlQUEUE* queue);
int wtlQueue_Length(wtlQUEUE* queue);
// 获取队列第一个元素,该操作不会删除节点信息
unsigned long wtlQueue_Front(wtlQUEUE* queue);
#endif /* _QUEUE_H_ */
queue.c队列的实现文件
#include <stdlib.h>
#include <assert.h>
#include "queue.h"
// 队列结构多了一个tail指针,不能直接调用list的创建函数了
wtlQUEUE* wtlQueue_Create(void){
wtlQUEUE* queue = malloc(
sizeof(*queue) + sizeof(wtlNODE) * 2 // 多申请两个wtlNODE的内存给header和tail
);
assert(queue != NULL);
queue->header = (wtlNODE*)(queue + 1); // 使header指向正确的位置
queue->tail = (wtlNODE*)(queue->header + 1); // 使tail指向正确的位置
queue->header->value = 0;
queue->header->next = NULL;
queue->tail->next = NULL;
return queue;
}
// 队列的销毁也不能直接调用链表的销毁操作
void wtlQueue_Destroy(wtlQUEUE** queue){
if (NULL == *queue) {
return;
}
// 下面这个循环只是释放了队列的node
wtlNODE* node = (*queue)->header->next;
while (node) {
(*queue)->header->next = node->next;
wtlNode_Destroy(&node);
node = (*queue)->header->next;
}
// 这里才释放队列的结构,包括header和tail
free(*queue);
*queue = NULL;
}
// 元素的入列操作,该操作不会保证元素的唯一性和有序性
void wtlQueue_Push(wtlQUEUE* queue, unsigned long value){
assert(queue != NULL);
wtlNODE* node = wtlNode_Create(value);
if (NULL == queue->header->next) {
queue->header->next = node;
queue->tail->next = node;
(queue->header->value)++;
return;
}
wtlNODE* last = queue->tail->next;
last->next = node;
queue->tail->next = node;
(queue->header->value)++;
}
unsigned long wtlQueue_Pop(wtlQUEUE* queue){
assert(queue != NULL);
unsigned long value = -1;
wtlNODE* first = queue->header->next;
if (NULL == first) {
return value;
}
queue->header->next = first->next;
value = first->value;
wtlNode_Destroy(&first);
(queue->header->value)--;
return value;
}
int wtlQueue_Length(wtlQUEUE* queue){
return (int)wtlList_Length((wtlLIST*)queue);
}
unsigned long wtlQueue_Front(wtlQUEUE* queue){
return wtlList_GetValue((wtlLIST*)queue, 0);
}
以上就是个人对几个线性数据结构的简单实现了,注释不是特别详细,学过数据结构的应该看下就能懂。