C语言之从简单的数据复合到列表的实现
列表LIST是LISP语言及其方言的重要数据类型,是由最基本的两个数据对象复合为一个数据对象开始的,这里试着用C语言数据结构来实现他!!!
复合两个对象的数据结构PAIR
- 定义Pair结构,包含两个成员:car和cdr
/* define pair data struct */
typedef struct _Pair Pair;
struct _Pair {void *car;void *cdr;
};
- 创建Pair函数: pair_new
- 创建Pair函数: cons,与pair_new功能相同,只是名字不一样
- 释放Pair函数: pair_free
- 取car的值函数: car
- 取cdr的值函数: cdr
- 设置car的值函数: set_car
- 设置cdr的值函数: set_cdr
代码如下:
/* filename : pair.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>/* define pair data struct */
typedef struct _Pair Pair;
struct _Pair {void *car;void *cdr;
};/* create a new pair */
Pair *
pair_new (void *a, void *d)
{Pair *p = (Pair*) malloc (sizeof(Pair));p->car = a; p->cdr = d;return p;
}/* also create a new pair */
Pair *
cons (void *a, void *d)
{Pair *p = (Pair*) malloc (sizeof(Pair));p->car = a; p->cdr = d;return p;
}/* get pair car */
void *
car (Pair *p)
{return p->car;
}/* get pair cdr */
void *
cdr (Pair *p)
{return p->cdr;
}/* set pair car */
void
set_car (Pair *p, void *v)
{p->car = v;
}/* set pair cdr */
void
set_cdr (Pair *p, void *v)
{p->cdr = v;
}/* free pair */
void
pair_free (Pair *p)
{free (p);
}/*-----------------------------------*//* test function */
void
test_pair (void)
{char *sa = "Hello";char *sd = "World";Pair *pa;pa = pair_new (sa, sd);printf ("CAR of pair : %s\n", (char*)car(pa));printf ("CDR of pair : %s\n", (char*)cdr(pa));pair_free (pa);printf ("--------------------\n");pa = cons (NULL, NULL);set_car (pa, "Aha...");set_cdr (pa, "Oho...");printf ("CAR of pair : %s\n", (char*)car(pa));printf ("CDR of pair : %s\n", (char*)cdr(pa));pair_free (pa);printf ("--------------------\n");printf ("Sizeof Pair : %lu\n", sizeof(Pair));
}/**/
int
main (int argc, char *argv[])
{test_pair ();return 0;
}
//-----(A.D)-----//
编译运行,达到预期,效果如下:
songvm@ubuntu:~/works/tmpc/boo$ gcc pair.c -o pair
songvm@ubuntu:~/works/tmpc/boo$ ./pair
CAR of pair : Hello
CDR of pair : World
--------------------
CAR of pair : Aha...
CDR of pair : Oho...
--------------------
Sizeof Pair : 16
songvm@ubuntu:~/works/tmpc/boo$
在PAIR的基础上构建列表LIST
- PAIR可以表示为 (car . cdr)
- LIST可以表示为:
- 空列表 ()
- 一个值的列表 (la . NULL),简化为: (la)
- 两个值的列表 (la . (lb . NULL)) 简化为: (la lb)
- 三个值的列表 (la . (lb . (lc . NULL))) 简化为: (la lb lc)
- 如此类推,也就是PAIR嵌套,最内部的PAIR的CDR为NULL,形成列表!!!
列表的创建、追加、释放和逐项操作
- list_new,创建列表函数
- append, preppend 追加,前追加函数
- list_free 释放函数
- list_each 逐项操作函数,需要一个函数指针,定义如下:
/* define function pointer */
typedef void (*LSFunc) (void *data);
- 代码如下:
/* create a new list with data */
Pair *
list_new (void *data)
{Pair *p = (Pair*) malloc (sizeof(Pair));p->car = data; p->cdr = NULL;return p;
}/* free the list */
void
list_free (Pair *lst)
{while (lst != NULL){void *at = car (lst);void *dt = cdr (lst);free (lst);lst = dt;}
}/* list each node call lsfunc */
void
list_each (Pair *lst, LSFunc lsfunc)
{while (lst != NULL){void *at = car (lst);void *dt = cdr (lst);lsfunc (at);lst = dt;}
}/* append data to list head*/
Pair *
list_append (Pair *head, void *data)
{Pair *p, *t = head;while (cdr(t) != NULL)t = cdr (t);p = cons (data, NULL);set_cdr (t, p);return head;
}/* preppend data to list head */
Pair *
list_preppend (Pair *head, void *data)
{return cons (data, head);
}
- 测试函数代码如下:
/* output string function, equal LSFunc */
void
out_string (void *data)
{printf ("%s ", (char*)data);
}/* test function for list_new list_append list_preppend */
void
test_list_new (void)
{char *buf[6] = {"AOE", "IUV", "BPM", "DTN", "GKH", "OOVOO"};Pair *la;la = list_new (buf[0]);for (int i = 1; i < 5; i++)la = list_append (la, buf[i]);la = list_preppend (la, buf[5]);list_each (la, out_string); printf ("\n");list_free (la);
}
编译运行,达到预期,测试内存分配情况,效果如下:
songvm@ubuntu:~/works/tmpc/boo$ gcc pair.c -o pair
songvm@ubuntu:~/works/tmpc/boo$ ./pair
OOVOO AOE IUV BPM DTN GKH
songvm@ubuntu:~/works/tmpc/boo$ valgrind --leak-check=yes ./pair
==7790== Memcheck, a memory error detector
==7790== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==7790== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==7790== Command: ./pair
==7790==
OOVOO AOE IUV BPM DTN GKH
==7790==
==7790== HEAP SUMMARY:
==7790== in use at exit: 0 bytes in 0 blocks
==7790== total heap usage: 7 allocs, 7 frees, 1,120 bytes allocated
==7790==
==7790== All heap blocks were freed -- no leaks are possible
==7790==
==7790== For counts of detected and suppressed errors, rerun with: -v
==7790== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
songvm@ubuntu:~/works/tmpc/boo$
创建多个节点列表,求列表长度
- list_new_n 函数
- list_length 函数
代码如下:
/* create a list from data */
Pair *
list_new_n (int n, void **data)
{Pair *r, *p;p = cons (data[0], NULL);r = p;for (int i = 1; i < n; i++){Pair *t = cons (data[i], NULL);set_cdr (p, t);p = t;}return r;
}/* get list length */
int
list_length (Pair *lst)
{int count = 0;if (lst == NULL) return 0;//if (cdr(lst) == NULL) return 1;while (lst != NULL){void *at = car (lst);void *dt = cdr (lst);count++;lst = dt;}return count;
}
- 测试函数,代码如下:
/* test function for list_new_n, list_each */
void
test_list_newn (void)
{char *buf[5] = {"Not", "only", "a", "test", "here!"};Pair *tp;tp = list_new_n (5, (void**)buf);list_each (tp, out_string); printf ("\n");printf ("List length : %d\n", list_length (tp));list_free (tp);
}
编译运行,顺利通过,效果如下:
songvm@ubuntu:~/works/tmpc/boo$ gcc pair.c -o pair
songvm@ubuntu:~/works/tmpc/boo$ ./pair
Not only a test here!
List length : 5
songvm@ubuntu:~/works/tmpc/boo$
取首节点、尾节点、第N个节点
- list_head 取首节点函数
- list_tail 取尾节点函数
- list_nth 取第N个节点函数
代码如下:
/* get head node */
void *
list_head (Pair *lst)
{return car (lst);
}/* get tail node */
void *
list_tail (Pair *lst)
{while (cdr(lst) != NULL){lst = cdr (lst);}return car (lst);
}/* get nth node */
void *
list_nth (Pair *lst, int nth)
{int idx = 0;while (lst != NULL){void *at = car (lst);void *dt = cdr (lst);idx++;if (idx == nth) return car(dt);lst = dt;}return NULL;
}
- 测试函数代码如下:
/* output long int equal LSFunc lsfunc */
void
out_long (void *data)
{printf ("%ld ", (long)data);
}/* test function for list_head, list_tail, list_nth */
void
test_list_get (void)
{Pair *lst;long ib[10] = {100, 101, 102, 103, 104, 105, 106, 107, 108, 109};lst = list_new ((void*)ib[0]);for (int i = 0; i < 10; i++)lst = list_append (lst, (void*)ib[i]);//list_each (lst, out_long); printf ("\n");printf ("HEAD : %ld\n", (long)list_head(lst));printf ("TAIL : %ld\n", (long)list_tail(lst));printf ("4TH : %ld\n", (long)list_nth(lst, 4));list_free (lst);
}
编译运行,达到预期,结果如下:
songvm@ubuntu:~/works/tmpc/boo$ gcc pair.c -o pair
songvm@ubuntu:~/works/tmpc/boo$ ./pair
HEAD : 100
TAIL : 109
4TH : 103
songvm@ubuntu:~/works/tmpc/boo$
倒转列表
- list_reverse函数
代码如下:
/* reverse the list */
Pair *
list_reverse (Pair *lst)
{Pair *p, *t = cdr(lst);p = cons (car(lst), NULL);while (t != NULL){Pair *a = car (t);Pair *d = cdr (t);p = cons (a, p);t = d;}return p;
}
- 测试函数代码如下:
/* test function list_reverse */
void
test_list_reverse (void)
{Pair *lst, *lsa;long ib[10] = {100, 101, 102, 103, 104, 105, 106, 107, 108, 109};lst = list_new ((void*)ib[0]);for (int i = 0; i < 10; i++)lst = list_append (lst, (void*)ib[i]);list_each (lst, out_long); printf ("\n");lsa = list_reverse (lst);list_each (lsa, out_long); printf ("\n");list_free (lst);list_free (lsa);
}
编译运行,达到预期,效果如下:
songvm@ubuntu:~/works/tmpc/boo$ gcc pair.c -o pair
songvm@ubuntu:~/works/tmpc/boo$ ./pair
100 101 102 103 104 105 106 107 108 109
109 108 107 106 105 104 103 102 101 100
songvm@ubuntu:~/works/tmpc/boo$
删除值为data的第一个节点
- 定义比较函数指针CMPFunc
- list_remove函数
代码如下:
/* define function pointer for list_remove */
typedef int (*CMPFunc) (void *x, void *y);/* remove list node equal data, test use cmpfunc */
Pair *
list_remove (Pair *lst, void *data, CMPFunc cmpfunc)
{Pair *rs = lst;while (lst != NULL){void *at = car (lst);if (0 == cmpfunc (at, data)){void *n = cdr (lst);set_car (lst, car (n));set_cdr (lst, cdr (n));pair_free (n);break;}lst = cdr (lst);}return rs;
}
- 测试函数代码如下:
/* compare long int if equal return 0 */
int
cmp_long (void *x, void *y)
{long a = (long)x, b = (long)y;if (x == y) return 0;else if (x > y) return x-y;else return x-y;
}/* test function list_remove */
void
test_list_remove (void)
{Pair *lst;long ib[10] = {100, 101, 102, 103, 104, 105, 106, 107, 108, 109};lst = list_new ((void*)ib[0]);for (int i = 1; i < 10; i++)lst = list_append (lst, (void*)ib[i]);list_each (lst, out_long); printf ("\n");lst = list_remove (lst, (void*)(106L), cmp_long);list_each (lst, out_long); printf ("\n");list_free (lst);
}
编译运行,达到预期,效果如下:
songvm@ubuntu:~/works/tmpc/boo$ gcc pair.c -o pair
songvm@ubuntu:~/works/tmpc/boo$ ./pair
100 101 102 103 104 105 106 107 108 109
100 101 102 103 104 105 107 108 109
songvm@ubuntu:~/works/tmpc/boo$
映射函数,将函数映射到列表的每一个节点,同时改变节点的值
- 定义函数指针MAPFunc
- list_map函数
代码如下:
/* function pointer for list_map */
typedef long (*MAPFunc) (void *val);/* map mapfunc on list each node */
void
list_map (Pair *lst, MAPFunc mapfunc)
{while (lst != NULL){set_car (lst, (void*)(mapfunc (car(lst))));lst = cdr (lst);}
}
- 测试函数代码如下:
/* for MAPFunc */
long
add_five (void *val)
{return (long)val + 5;
}/* test function list_map */
void
test_list_map (void)
{Pair *lst;long ib[10] = {100, 101, 102, 103, 104, 105, 106, 107, 108, 109};lst = list_new ((void*)ib[0]);for (int i = 1; i < 10; i++)lst = list_append (lst, (void*)ib[i]);list_each (lst, out_long); printf ("\n");list_map (lst, add_five);list_each (lst, out_long); printf ("\n");list_free (lst);
}
编译运行,达到预期,效果如下:
songvm@ubuntu:~/works/tmpc/boo$ gcc pair.c -o pair
songvm@ubuntu:~/works/tmpc/boo$ ./pair
100 101 102 103 104 105 106 107 108 109
105 106 107 108 109 110 111 112 113 114
songvm@ubuntu:~/works/tmpc/boo$
完整代码如下:
/* filename : pair.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>/* define pair data struct */
typedef struct _Pair Pair;
struct _Pair {void *car;void *cdr;
};/* define function pointer */
typedef void (*LSFunc) (void *data);/* create a new pair */
Pair *
pair_new (void *a, void *d)
{Pair *p = (Pair*) malloc (sizeof(Pair));p->car = a; p->cdr = d;return p;
}/* also create a new pair */
Pair *
cons (void *a, void *d)
{Pair *p = (Pair*) malloc (sizeof(Pair));p->car = a; p->cdr = d;return p;
}/* get pair car */
void *
car (Pair *p)
{return p->car;
}/* get pair cdr */
void *
cdr (Pair *p)
{return p->cdr;
}/* set pair car */
void
set_car (Pair *p, void *v)
{p->car = v;
}/* set pair cdr */
void
set_cdr (Pair *p, void *v)
{p->cdr = v;
}/* free pair */
void
pair_free (Pair *p)
{free (p);
}/* create a new list with data */
Pair *
list_new (void *data)
{Pair *p = (Pair*) malloc (sizeof(Pair));p->car = data; p->cdr = NULL;return p;
}/* create a list from data */
Pair *
list_new_n (int n, void **data)
{Pair *r, *p;p = cons (data[0], NULL);r = p;for (int i = 1; i < n; i++){Pair *t = cons (data[i], NULL);set_cdr (p, t);p = t;}return r;
}/* free the list */
void
list_free (Pair *lst)
{while (lst != NULL){void *at = car (lst);void *dt = cdr (lst);free (lst);lst = dt;}
}/* list each node call lsfunc */
void
list_each (Pair *lst, LSFunc lsfunc)
{while (lst != NULL){void *at = car (lst);void *dt = cdr (lst);lsfunc (at);lst = dt;}
}/* get list length */
int
list_length (Pair *lst)
{int count = 0;if (lst == NULL) return 0;//if (cdr(lst) == NULL) return 1;while (lst != NULL){void *at = car (lst);void *dt = cdr (lst);count++;lst = dt;}return count;
}/* append data to list head*/
Pair *
list_append (Pair *head, void *data)
{Pair *p, *t = head;while (cdr(t) != NULL)t = cdr (t);p = cons (data, NULL);set_cdr (t, p);return head;
}/* preppend data to list head */
Pair *
list_preppend (Pair *head, void *data)
{return cons (data, head);
}/* get head node */
void *
list_head (Pair *lst)
{return car (lst);
}/* get tail node */
void *
list_tail (Pair *lst)
{while (cdr(lst) != NULL){lst = cdr (lst);}return car (lst);
}/* get nth node */
void *
list_nth (Pair *lst, int nth)
{int idx = 0;while (lst != NULL){void *at = car (lst);void *dt = cdr (lst);idx++;if (idx == nth) return car(dt);lst = dt;}return NULL;
}/* reverse the list */
Pair *
list_reverse (Pair *lst)
{Pair *p, *t = cdr(lst);p = cons (car(lst), NULL);while (t != NULL){Pair *a = car (t);Pair *d = cdr (t);p = cons (a, p);t = d;}return p;
}/* define function pointer for list_remove */
typedef int (*CMPFunc) (void *x, void *y);/* remove list node equal data, test use cmpfunc */
Pair *
list_remove (Pair *lst, void *data, CMPFunc cmpfunc)
{Pair *rs = lst;while (lst != NULL){void *at = car (lst);if (0 == cmpfunc (at, data)){void *n = cdr (lst);set_car (lst, car (n));set_cdr (lst, cdr (n));pair_free (n);break;}lst = cdr (lst);}return rs;
}/* function pointer for list_map */
typedef long (*MAPFunc) (void *val);/* map mapfunc on list each node */
void
list_map (Pair *lst, MAPFunc mapfunc)
{while (lst != NULL){set_car (lst, (void*)(mapfunc (car(lst))));lst = cdr (lst);}
}/*-----------------------------------*//* test function for pair */
void
test_pair (void)
{char *sa = "Hello";char *sd = "World";Pair *pa;pa = pair_new (sa, sd);printf ("CAR of pair : %s\n", (char*)car(pa));printf ("CDR of pair : %s\n", (char*)cdr(pa));pair_free (pa);printf ("--------------------\n");pa = cons (NULL, NULL);set_car (pa, "Aha...");set_cdr (pa, "Oho...");printf ("CAR of pair : %s\n", (char*)car(pa));printf ("CDR of pair : %s\n", (char*)cdr(pa));pair_free (pa);printf ("--------------------\n");printf ("Sizeof Pair : %lu\n", sizeof(Pair));
}/* output string function, equal LSFunc */
void
out_string (void *data)
{printf ("%s ", (char*)data);
}/* test function for list_new list_append list_preppend */
void
test_list_new (void)
{char *buf[6] = {"AOE", "IUV", "BPM", "DTN", "GKH", "OOVOO"};Pair *la;la = list_new (buf[0]);for (int i = 1; i < 5; i++)la = list_append (la, buf[i]);la = list_preppend (la, buf[5]);list_each (la, out_string); printf ("\n");list_free (la);
}/* test function for list_new_n, list_each */
void
test_list_newn (void)
{char *buf[5] = {"Not", "only", "a", "test", "here!"};Pair *tp;tp = list_new_n (5, (void**)buf);list_each (tp, out_string); printf ("\n");printf ("List length : %d\n", list_length (tp));list_free (tp);
}/* output long int equal LSFunc lsfunc */
void
out_long (void *data)
{printf ("%ld ", (long)data);
}/* test function for list_head, list_tail, list_nth */
void
test_list_get (void)
{Pair *lst;long ib[10] = {100, 101, 102, 103, 104, 105, 106, 107, 108, 109};lst = list_new ((void*)ib[0]);for (int i = 1; i < 10; i++)lst = list_append (lst, (void*)ib[i]);//list_each (lst, out_long); printf ("\n");printf ("HEAD : %ld\n", (long)list_head(lst));printf ("TAIL : %ld\n", (long)list_tail(lst));printf ("4TH : %ld\n", (long)list_nth(lst, 4));list_free (lst);
}/* test function list_reverse */
void
test_list_reverse (void)
{Pair *lst, *lsa;long ib[10] = {100, 101, 102, 103, 104, 105, 106, 107, 108, 109};lst = list_new ((void*)ib[0]);for (int i = 1; i < 10; i++)lst = list_append (lst, (void*)ib[i]);list_each (lst, out_long); printf ("\n");lsa = list_reverse (lst);list_each (lsa, out_long); printf ("\n");list_free (lst);list_free (lsa);
}/* compare long int if equal return 0 */
int
cmp_long (void *x, void *y)
{long a = (long)x, b = (long)y;if (x == y) return 0;else if (x > y) return x-y;else return x-y;
}/* test function list_remove */
void
test_list_remove (void)
{Pair *lst;long ib[10] = {100, 101, 102, 103, 104, 105, 106, 107, 108, 109};lst = list_new ((void*)ib[0]);for (int i = 1; i < 10; i++)lst = list_append (lst, (void*)ib[i]);list_each (lst, out_long); printf ("\n");lst = list_remove (lst, (void*)(106L), cmp_long);list_each (lst, out_long); printf ("\n");list_free (lst);
}/* for MAPFunc */
long
add_five (void *val)
{return (long)val + 5;
}/* test function list_map */
void
test_list_map (void)
{Pair *lst;long ib[10] = {100, 101, 102, 103, 104, 105, 106, 107, 108, 109};lst = list_new ((void*)ib[0]);for (int i = 1; i < 10; i++)lst = list_append (lst, (void*)ib[i]);list_each (lst, out_long); printf ("\n");list_map (lst, add_five);list_each (lst, out_long); printf ("\n");list_free (lst);
}/**/
int
main (int argc, char *argv[])
{//test_pair ();//test_list_new ();//test_list_newn ();//test_list_get ();//test_list_reverse ();//test_list_remove ();test_list_map ();return 0;
}
//-----(A.D)-----//
- 测试的不够充分,有想进一步研究的朋友可以琢磨下!!!