高级语言里的列表是最常用的数据结构,在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. laravel中日志为daily时如何设置最大保存天数

    在laravel中,日志设置为daily时,默认保存七天的日志,超过则清除七天前的日志.可修改默认的设置,假如要保存30天的日志,则配置如下: 在配置文件config/app.php中添加如下代码: ...

  2. .net操作word lib DocX

    http://cathalscorner.blogspot.hk/2010/06/cathal-why-did-you-create-docx.html using (DocX document = ...

  3. hadoop-mongo map/reduce java

    官方 http://docs.mongodb.org/ecosystem/tutorial/getting-started-with-hadoop/ mongo-haoop项目地址 https://g ...

  4. ng animate

    要在angular中加入动画必须引入angular.animate.js插件,然后就可以在module中引入ngAnimate模块.如: var module1 = angular.module('m ...

  5. netty学习

    1.不选择java原生nio的原因   (1)nio的类库和api繁杂   (2)需要具备其他的额外的技能做铺垫,例如熟悉java多线程编程.   (3)可靠性能力补齐的工作量和难度都非常大,例如客户 ...

  6. 跟我学-Java底层技术系列文章

    对于工作中经常用到的东西,还是多看看实现原理,这样用着才能放心. 源码思想学习计划: 1.java基础库  HashCode深入理解 java线程框架窥探 2.集合类     java枚举类使用 递归 ...

  7. 判断Window在哪个屏幕

    最近在做窗口最大化时需要一个功能,如果是多个显示器的话,需要在当前显示器最大化,由于是根据屏幕长宽进行设置Window大小,没有使用WindowState.Maximized,window.Left不 ...

  8. HTML5+CSS3学习笔记(一)

    HTML5+CSS3概述 HTML5和CSS3不仅仅是两项新的Web技术标准,更代表了下一代HTML和CSS技术.虽然HTML5的标准规范还没有正式发布,但是未来的发展前景已经可以预见,那就是HTML ...

  9. Mvc 简单分页代码

    ) { string userid = EndUserLoginManage.Instance.loginUserID; ICommentInfoBLL c_bll = new CommentInfo ...

  10. Android WebView 重定向问题

    webView.setWebViewClient(new WebViewClient() { @Override public boolean shouldOverrideUrlLoading(Web ...