快速学习C语言四: 造轮子,ArrayList
高级语言里的列表是最常用的数据结构,在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的更多相关文章
- 快速学习C语言一: Hello World
估计不会写C语言的同学也都听过C语言,从头开始快速学一下吧,以后肯定能用的上. 如果使用过其它类C的语言,如JAVA,C#等,学C的语法应该挺快的. 先快速学习并练习一些基本的语言要素,基本类型,表达 ...
- 快速学习C语言三: 开发环境, VIM配置, TCP基础,Linux开发基础,Socket开发基础
上次学了一些C开发相关的工具,这次再配置一下VIM,让开发过程更爽一些. 另外再学一些linux下网络开发的基础,好多人学C也是为了做网络开发. 开发环境 首先得有个Linux环境,有时候家里机器是W ...
- 快速学习C语言二: 编译自动化, 静态分析, 单元测试,coredump调试,性能剖析
上次的Hello world算是入门了,现在学习一些相关工具的使用 编译自动化 写好程序,首先要编译,就用gcc就好了,基本用法如下 gcc helloworld.c -o helloworld.o ...
- 快速学习C语言途径,让你少走弯路
1.标准C语言能干什么? 坦白讲,在今天软件已经发展了半个多世纪,单纯的C语言什么都干不了.标准C语言库只提供了一些通用的逻辑运算方法以及字符串处理,当然字符串在C语言看来也是一种操作内存的方法,所以 ...
- 造轮子ArrayList
这篇博客实现一个简单的ArrayList集合.博客里的代码首先根据自己的想法实现,在走不动的情况下会去参考JDK源代码.所以阅读本文,不要抱着跟JDK源码对比的心态.于我个人而言,国庆期间,纯属娱乐. ...
- Vue快速学习_第四节
获取原生的DOM方式($.refs) 给标签或者组件 添加ref <div ref = 'liu'>test</div> <Home ref = 'home'>&l ...
- 一起学习造轮子(一):从零开始写一个符合Promises/A+规范的promise
本文是一起学习造轮子系列的第一篇,本篇我们将从零开始写一个符合Promises/A+规范的promise,本系列文章将会选取一些前端比较经典的轮子进行源码分析,并且从零开始逐步实现,本系列将会学习Pr ...
- 如何快速高效率地学习Go语言
要想快速高效率地掌握Go语言,关键是要通过不断写代码去训练,熟能生巧.方法是没问题的,但具体的路径呢?就像开车,能不能给个导航?我希望这篇文章能起到一个导航的作用,这里提供的路径,应该对很多人都适合. ...
- c语言学习之第四章
第四章 第四章主要介绍了分支结构,循环结构的简单使用,还有其他简单的语句结束语句,比如,break,continue.还有gote语句.下面是我学习C语言第四章的一些心得和总结. 1简单的if语句 简 ...
随机推荐
- php获取数据库中数据,转成json数据
<?php //需要执行的SQL语句 //单条 $sql="select * from xinwen"; //多条数据 //$sql="select id,name ...
- sql 将8位字符串转换成日期型
将8位字符串转换成日期型,方法如下: ),)
- CS0012: 类型“System.Data.Objects.DataClasses.EntityObject”在未被引用的程序集中定义
entity framework,没在view引用 实体对象时,一直没问题,引用后爆出这个错误来 CS0012: 类型"System.Data.Objects.DataClasses.En ...
- C# 5.0新推出的async和await
class Program { static void Main(string[] args) { Test t = new Test(); } } public class Test { publi ...
- VBA操作单元格
行或列的Group化 ws.Rows("row1:row2").group row1:Group化的开始行 row2:Group化的结束行 ws.Co ...
- c++ 课堂作业(1)
一.题目 Create a program that asks for the radius of a circle and prints the area of that circle, using ...
- Android LayoutInflater原理分析,带你一步步深入了解View(一)
转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/12921889 有不少朋友跟我反应,都希望我可以写一篇关于View的文章,讲一讲Vi ...
- 记一次FTP上传文件总是超时的解决过程
好久没写博,还是重拾记录一下吧. 背景:买了一个阿里云的云虚拟机用来搭建网站(起初不了解云虚拟主机和云服务器的区别,以为都是有SSH功能的,后来发现不是这样样子啊,云虚拟机就是FTP上传网页+MySQ ...
- load与initialize
NSObject类有两种初始化方式load和initialize load + (void)load; 对于加入运行期系统的类及分类,必定会调用此方法,且仅调用一次. iOS会在应用程序启动的时候调用 ...
- session和cookie的简单理解
0. 引子,我们为什么要cookie和session 因为http请求是无状态的(不能记录用户的登录状态等),所以需要某种机制来保存用户的登录状态等信息,在下次访问web服务的时候,不用再 ...