高级语言里的列表是最常用的数据结构,在C里造个轮子玩玩,C没有泛型,先用int练习。

Collection的ADT一般有hasnext,next,add, remove操作,List一般还加了removeat, insert等,然后Stack有push和pop,Queue有enqueue和dequeue。列表有种实现, ArrayList和LinkedList,总体来说ArrayList更常用一些,就先用数组实现个列表。

ArrayList在末尾的添加和删除还是挺快的(O(1)),所以当栈来用挺好,Push和Pop都在末尾。 当队列的话,Enqueue在数组头部放入元素,所有右边的元素都要向右移动(O(N)),比较耗 时,不如LinkedList。另外获取指定索引数据或设置指定索引的数据是O(1)复杂度, 比LinkedList快,如果要想查看是否有指定数据,或删除指定数据,要扫描全表,复杂度 是O(N)。哦,删除指定位置的数据复杂度也是O(N), 因为删除后右边的数据要全部向 左移动。

可以开始了,首先定义一个结构来保存状态

struct arr_list {
int * arr; // 内部数组
int index; // 实际数据大小
int size; // 预分配空间大小
};

创建一个array list

struct arr_list* create_arr_list(n) {
if (n < ) {
n = ;
}
struct arr_list *arr = (struct arr_list*)malloc(sizeof(struct arr_list));
arr->arr = (int*)malloc(sizeof(int) * n);
arr->size = n;
arr->index = ;
return arr;
}

空间不足时自动扩容,默认策略是空间不够时申请双倍大小空间, 然后把原有数据拷贝到 新空间,并把原有空间释放掉, 该函数一般是新增元素前调用,所以判断条件是当实际 所用空间已经等于或大于(应该不可能)预分配空间时扩容。

static void expand_space(struct arr_list *arr) {
int *tmp, i, *p, *q; if (arr->index >= arr->size) {
tmp = (int *)malloc(sizeof(int) * arr->size * );
p = arr->arr;
q = tmp;
for (i = ; i < arr->index; i++) {
*q++ = *p++;
}
free(arr->arr);
arr->arr = tmp;
arr->size = arr->size * ;
}
}

在指定位置插入新元素,现有元素向右移,O(N)

int list_insert(struct arr_list *arr, int index, int obj) {
int i; if (index < || index > arr->index) {
return -;
}
expand_space(arr); for (i = arr->index; i > index ; i--) {
arr->arr[i] = arr->arr[i - ];
}
arr->arr[index] = obj;
arr->index++;
return ;
}

在array list 末尾插入数据, O(1)

int list_push(struct arr_list *arr, int obj) {
return list_insert(arr, arr->index, obj);
}

删除指定位置的数据,O(N), 删除数据后,所有数据向左移动

int list_removeat(struct arr_list *arr, int index) {
int i;
if (index < || index >= arr->index) {
return -;
}
for (i = index; i < arr->index - ; i++) {
arr->arr[index] = arr->arr[index + ];
}
arr->index--;
return ;
}

移除并返回末尾的数据, O(1)

int list_pop(struct arr_list *arr) {
return list_removeat(arr, arr->index - );
}

判断 array list里是否包含某个数据, O(N)

int list_index(const struct arr_list *arr, int obj) {
int i;
for (i = ; i < arr->index; i++) {
if (arr->arr[i] == obj) {
return i;
}
}
return -;
}

删除某个数据项,O(N), 只删第一次出现的位置, 删除后所有数据向左移动

int list_remove(struct arr_list *arr, int obj) {
int i, index;
index = list_index(arr, obj);
if (index != -) {
for (i = index; i < arr->index - ; i++) {
arr->arr[i] = arr->arr[i + ];
}
arr->index--;
}
return index;
}

释放一个array list的内存

int free_arr_list(struct arr_list *arr){
free(arr->arr);
free(arr);
return ;
}

从头打印一个arr list

void print_arr_list(const struct arr_list *arr) {
int i, t;
printf("size=%d,index=%d\n", arr->size, arr->index);
for (i = ; i < arr->index; i++) {
list_get(arr, i, &t);
printf("list[%d]=%d\n", i, t);
}
}

最后整体测试一下

int main(void)
{
struct arr_list *arr;
int r; arr = create_arr_list();
printf("list push: 5, 6, 7\n");
list_push(arr, );
list_push(arr, );
list_push(arr, );
print_arr_list(arr); printf("list push: 8, will auto expand\n");
list_push(arr, );
print_arr_list(arr); printf("list remove at 2\n");
list_removeat(arr, );
print_arr_list(arr); printf("list pop \n");
list_pop(arr);
print_arr_list(arr); printf("list insert 0\n");
list_insert(arr, , );
print_arr_list(arr); r = list_index(arr, );
printf("list index 3:%d\n", r);
r = list_index(arr, );
printf("list index 7:%d\n", r); printf("list remove 3\n");
list_remove(arr, );
print_arr_list(arr); printf("list set index 0 = 3\n");
list_set(arr, , );
print_arr_list(arr); free_arr_list(arr);
return ;
}

小结

用C实现一下高级语言里常用的数据结构,可以对它们有更深的理解。

快速学习C语言四: 造轮子,ArrayList的更多相关文章

  1. 快速学习C语言一: Hello World

    估计不会写C语言的同学也都听过C语言,从头开始快速学一下吧,以后肯定能用的上. 如果使用过其它类C的语言,如JAVA,C#等,学C的语法应该挺快的. 先快速学习并练习一些基本的语言要素,基本类型,表达 ...

  2. 快速学习C语言三: 开发环境, VIM配置, TCP基础,Linux开发基础,Socket开发基础

    上次学了一些C开发相关的工具,这次再配置一下VIM,让开发过程更爽一些. 另外再学一些linux下网络开发的基础,好多人学C也是为了做网络开发. 开发环境 首先得有个Linux环境,有时候家里机器是W ...

  3. 快速学习C语言二: 编译自动化, 静态分析, 单元测试,coredump调试,性能剖析

    上次的Hello world算是入门了,现在学习一些相关工具的使用 编译自动化 写好程序,首先要编译,就用gcc就好了,基本用法如下 gcc helloworld.c -o helloworld.o ...

  4. 快速学习C语言途径,让你少走弯路

    1.标准C语言能干什么? 坦白讲,在今天软件已经发展了半个多世纪,单纯的C语言什么都干不了.标准C语言库只提供了一些通用的逻辑运算方法以及字符串处理,当然字符串在C语言看来也是一种操作内存的方法,所以 ...

  5. 造轮子ArrayList

    这篇博客实现一个简单的ArrayList集合.博客里的代码首先根据自己的想法实现,在走不动的情况下会去参考JDK源代码.所以阅读本文,不要抱着跟JDK源码对比的心态.于我个人而言,国庆期间,纯属娱乐. ...

  6. Vue快速学习_第四节

    获取原生的DOM方式($.refs) 给标签或者组件 添加ref <div ref = 'liu'>test</div> <Home ref = 'home'>&l ...

  7. 一起学习造轮子(一):从零开始写一个符合Promises/A+规范的promise

    本文是一起学习造轮子系列的第一篇,本篇我们将从零开始写一个符合Promises/A+规范的promise,本系列文章将会选取一些前端比较经典的轮子进行源码分析,并且从零开始逐步实现,本系列将会学习Pr ...

  8. 如何快速高效率地学习Go语言

    要想快速高效率地掌握Go语言,关键是要通过不断写代码去训练,熟能生巧.方法是没问题的,但具体的路径呢?就像开车,能不能给个导航?我希望这篇文章能起到一个导航的作用,这里提供的路径,应该对很多人都适合. ...

  9. c语言学习之第四章

    第四章 第四章主要介绍了分支结构,循环结构的简单使用,还有其他简单的语句结束语句,比如,break,continue.还有gote语句.下面是我学习C语言第四章的一些心得和总结. 1简单的if语句 简 ...

随机推荐

  1. java web(spring mvc) 获取请求host 和 如何获取静态页的相对路径

    1.获取请求host StringBuffer url = request.getRequestURL(); String tempContextUrl = url.delete(url.length ...

  2. apache结合svn创建svn资源库

    1.在登录过程中可以查看error日志,如果发生以下提示: (13)Permission denied: Could not open password file 2.运行:chcon -R -h - ...

  3. 【Leetcode-Mysql】Trips and Users

    思路不总结了,看过题目自己尝试过之后,看下方代码应该能理解的 SELECT Request_at AS DAY, round( sum( CASE WHEN STATUS = 'completed' ...

  4. 远程debug hadoop

  5. oracle for loop循环以及游标循环

    1. for in loop形式 DECLARE    CURSOR c_sal IS SELECT employee_id, first_name || last_name ename, salar ...

  6. C#捕获c++异常

    摘自:http://bbs.csdn.net/topics/390665130 .net 40 中,c# 默认情况下只处理SEH的异常.不处理CSE的异常.若你要捕获这类的异常. [HandlePro ...

  7. 由React学习到Yeoman安装以及遇到的问题

    离职闲下来之后想着学一些新知识,本来是想从react入手,结果延伸出去的内容就像一棵树的树枝,不断增加. 学习计划是从这里开始的(6周学习计划,攻克javascript难关 https://zhuan ...

  8. 《深入理解Spark:核心思想与源码分析》——SparkContext的初始化(叔篇)——TaskScheduler的启动

    <深入理解Spark:核心思想与源码分析>一书前言的内容请看链接<深入理解SPARK:核心思想与源码分析>一书正式出版上市 <深入理解Spark:核心思想与源码分析> ...

  9. Being a Good Boy in Spring Festival 尼姆博弈

    Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Descr ...

  10. 移动端H5页面的最佳终端适配之Flexible

    lib-flexible是什么? lib-flexible是一个制作H5适配的开源库,可以点击这里下载相关文件,获取需要的JavaScript和CSS文件. 当然你可以直接使用阿里CDN: <s ...