读书笔记 ——《系统程序员成长计划》篇7:动态数组
说明:
本文章旨在总结备份、方便以后查询,由于是个人总结,如有不对,欢迎指正;另外,内容大部分来自网络、书籍、和各类手册,如若侵权请告知,马上删帖致歉。
QQ 群 号:513683159 【相互学习】
内容来源:
《系统程序员成长计划》、C语言实现动态数组,克服静态数组大小固定的缺陷
上一篇:读书笔记 ——《系统程序员成长计划》篇6:写的又快又好的秘诀
下一篇:读书笔记 ——《系统程序员成长计划》篇8:排序算法
目录:
- 一、概念
- 1、什么是动态数组?
- 2、双向链表和动态数组的对比
- 二、动态数据的实现
- 1、简单实现
- 2、书中示例 关键函数简述
- (1)动态数组 结构体
- (2)动态数组 创建函数
- (3)动态数组 扩展函数
- (4)动态数组 减小函数
- (5)动态数组 插入函数(包含头插法与尾插法)
- (6)动态数组 删除函数
- (7)动态数组 销毁函数
- 3.书中程序
- typedef.h
- darray.h
- darray.c
- Makefile
一、概念
1、什么是动态数组?
C语言中,数组长度必须在创建时指定,且只能是常数不能是变量。定义后系统将为它分配固定大小的空间,以后不能改变,称为静态数组。但在编程过程中,有时所需的内存空间无法预先确定,故用静态数组的办法很难解决。
动态数组可随程序需要而重新指定大小。通过执行代码在内存空间从堆(heap)上分配(即动态分配)的。当程序执行到这些语句时,才为其分配。程序员自己负责释放内存。
2、双向链表和动态数组的对比
情形 | 动态数组 | 双向链表 |
空间占用情况 | 占用一块连续的内存 | 每个结点占用一块内存 |
频繁增删数据 | 需移动后面元素 | 只需修改前后元素指针,但容易造成内存碎片 |
是否支持多种高效排序算法 | 支持,如:快速排序、归并排序,堆排序等 | 表现不好,甚至不如冒泡排序 |
排序好的数据 | 可使用二分查找 | 仍只能用顺序查找 |
小量数据 | 区别不大 | 区别不大 |
二、动态数据的实现
同样选择存指针,故实现的是指针数组。
1、简单实现
#include <stdio.h>
#include <stdlib.h>
int main(){int arrLen; // 数组长度int *array; // 数组指针int i; // 数组下标printf("输入数组长度:");scanf("%d", &arrLen);// 动态分配内存空间,如果失败就退出程序array = (int*)malloc( arrLen*sizeof(int) );if(!array){printf("创建数组失败!\n");exit(1); }// 向内存中写入数据for(i=0; i<arrLen; i++){array[i] = i+1;} // 循环输出数组元素for(i=0; i<arrLen; i++){printf("%d ", array[i]);}printf("\n");free(array); return 0;
}
实现现象:
输入数组长度:20
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
这边定义了数组指针,指向malloc
函数创建的一整块内存空间,实现动态数组,动态输入数组长度后自动赋值数据并输出。实际上与静态数组并没有什么区别。
2、书中示例 关键函数简述
(1)动态数组 结构体
struct _DArray;
typedef struct _DArray DArray;
typedef void (*DataDestroyFunc)(void* ctx, void* data);struct _DArray
{void** data; //数据size_t size; //实际使用大小size_t alloc_size; //分配空间大小void* data_destroy_ctx; //销毁函数中上下文数据DataDestroyFunc data_destroy; //函数指针,为指向销毁函数
};
(2)动态数组 创建函数
/*** @function:动态数组 创建函数* * @param data_destroy: 使用者编写的销毁函数的函数指针* @param ctx: 销毁函数中的上下文数据* * @return: 指向该动态数组地址* @description:* 开辟一块动态数组结构体大小的空间,并赋初始值。
*/
DArray* darray_create(DataDestroyFunc data_destroy, void* ctx)
{DArray* thiz = malloc(sizeof(DArray)); //分配空间if(thiz != NULL) //若成功分配则对结构体变量初始化{thiz->data = NULL;thiz->size = 0;thiz->alloc_size = 0;thiz->data_destroy = data_destroy;thiz->data_destroy_ctx = ctx;}return thiz;
}
(3)动态数组 扩展函数
/*** @function:动态数组 扩展函数* * @param thiz: 指向动态数组* @param need: 所需动态数组大小* * @return: 运行状态* @description:* 扩展数组时,并不是一次扩展一个元素,而是多个元素,1.5倍为作者的经验所得
*/
#define MIN_PRE_ALLOCATE_NR 10
static Ret darray_expand(DArray* thiz, size_t need)
{return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); //若不存在则直接返回错误if((thiz->size + need) > thiz->alloc_size) //若现用大小+所需大小 > 现有实际大小{size_t alloc_size = thiz->alloc_size + (thiz->alloc_size>>1) + MIN_PRE_ALLOCATE_NR;//扩大为原来的1.5倍并加上常数void** data = (void**)realloc(thiz->data, sizeof(void*) * alloc_size); //重新分配大小if(data != NULL){thiz->data = data;thiz->alloc_size = alloc_size;}}return ((thiz->size + need) <= thiz->alloc_size) ? RET_OK : RET_FAIL; //判断是否执行成功
}
①函数简介:
realloc()
函数:尝试重新调整之前调用 malloc
或 calloc
所分配的ptr
所指向的内存块的大小
函数原型:void *realloc(void *ptr, size_t size)
参数:
1️⃣ ptr
– 指针指向一个要重新分配内存的内存块,该内存块之前是通过调用 malloc
、calloc
或 realloc
进行分配内存的。如果为空指针,则会分配一个新的内存块,且函数返回一个指向它的指针。
2️⃣ size
– 内存块的新的大小,以字节为单位。如果大小为 0,且 ptr 指向一个已存在的内存块,则 ptr 所指向的内存块会被释放,并返回一个空指针。
返回值:
该函数返回一个指针 ,指向重新分配大小的内存。如果请求失败,则返回 NULL。
②扩展1.5倍的公式:size_t alloc_size = thiz->alloc_size + (thiz->alloc_size>>1) + MIN_PRE_ALLOCATE_NR;
为什么要用这个公式呢?
大多数嵌入式平台并不支持硬件浮点数计算,浮点数的计算要比定点数计算要慢,故并不是直接使用1.5*thiz->alloc_size
.又由于若编译器不做优化,则除法操作也较慢,故也不使用thiz->alloc_size+thiz->alloc_size/2
.
而size_t alloc_size = thiz->alloc_size + (thiz->alloc_size>>1)
则是最快的方法。后面加上MIN_PRE_ALLOCATE_NR
是为避免当thiz->alloc_size
为0时存在的错误。
(4)动态数组 减小函数
/*** @function:动态数组 减小空间函数* * @param thiz: 指向动态数组* @return: 运行状态* @description:* 当 实际空间大小的一半 还大于当前数组大小 且 实际空间大小 要大于 固定值 (预防为0的情况)时,减小为有效空间的1.5倍。* 注:删除元素时也并不是马上释放空间,而是等空闲空间高于某个值才释放它们。
*/
static Ret darray_shrink(DArray* thiz)
{return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); //若不存在则直接返回错误if((thiz->size < (thiz->alloc_size >> 1)) && (thiz->alloc_size > MIN_PRE_ALLOCATE_NR))//若现有大小 < 已分配1/2倍 且 已分配空间>最小空间{size_t alloc_size = thiz->size + (thiz->size >> 1); //将空间大小缩小为现有的1.5倍void** data = (void**)realloc(thiz->data, sizeof(void*) * alloc_size);if(data != NULL){thiz->data = data;thiz->alloc_size = alloc_size;}}return RET_OK;
}
(5)动态数组 插入函数(包含头插法与尾插法)
/*** @function:动态数组 插入函数* * @param thiz: 指向动态数组* @param index: 插入的位置* @param data: 插入的数据* * @return: 运行状态* @description:
*/
Ret darray_insert(DArray* thiz, size_t index, void* data)
{Ret ret = RET_OOM; //定义返回状态初始值为OOMsize_t cursor = index; //形参:数组下标或称游标(插入的位置)return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); //若对象为空,则报错为无效参数cursor = cursor < thiz->size ? cursor : thiz->size; //确认插入元素的位置if(darray_expand(thiz, 1) == RET_OK) //若成功扩展空间,则将游标以后位置数据后移一个单位后,将指定位置赋值且数组长度变量+1{size_t i = 0;for(i = thiz->size; i > cursor; i--){thiz->data[i] = thiz->data[i-1];}thiz->data[cursor] = data;thiz->size++;ret = RET_OK;}return ret;
}/*** @function: 头插法* * @param thiz: 指向动态数组* @param data: 插入的数据* * @return: 运行状态* @description:
*/
Ret darray_prepend(DArray* thiz, void* data)
{return darray_insert(thiz, 0, data);
}/** * @function: 尾插法* * @param thiz: 指向动态数组* @param data: 插入的数据* * @return: 运行状态* @description:
*/
Ret darray_append(DArray* thiz, void* data)
{return darray_insert(thiz, -1, data);
}
(6)动态数组 删除函数
/*** @function: 动态数组 删除数据* * @param thiz: 指向动态数组* @param data: 数据* * @return: 无* @description:* 销毁函数在创建时有使用者进行编写
*/
static void darray_destroy_data(DArray* thiz, void* data)
{if(thiz->data_destroy != NULL){thiz->data_destroy(thiz->data_destroy_ctx, data);}return;
}/*** @function:动态数组 删除函数* * @param thiz: 指向动态数组对象* @param index: 指定下标位置* * @return: 执行状态* @description:* 删除指定位置数据,数组元素前移。
*/
Ret darray_delete(DArray* thiz, size_t index)
{size_t i = 0;Ret ret = RET_OK;return_val_if_fail(thiz != NULL && thiz->size > index, RET_INVALID_PARAMS); //若动态数组不存在且删除位置大于数组大小darray_destroy_data(thiz, thiz->data[index]); //删除指定位置数据for(i = index; (i+1) < thiz->size; i++) //将删除后的数组元素前移{thiz->data[i] = thiz->data[i+1];}thiz->size--;darray_shrink(thiz); //检查是否需要减小空间return RET_OK;
}
(7)动态数组 销毁函数
/*** @function: 动态数组 销毁函数* * @param thiz: 指向动态数组* * @return: 无* @description:* 删除所有数据,销毁动态数组,销毁动态数组空间
*/
void darray_destroy(DArray* thiz)
{size_t i = 0;if(thiz != NULL){for(i = 0; i < thiz->size; i++){darray_destroy_data(thiz, thiz->data[i]);}SAFE_FREE(thiz->data);SAFE_FREE(thiz);}return;
}
3.书中程序
typedef.h
/** File: typedef.h* Author: Li XianJing <xianjimli@hotmail.com>* Brief: common types definition.** Copyright (c) Li XianJing** Licensed under the Academic Free License version 2.1** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*//** History:* ================================================================* 2008-12-10 Li XianJing <xianjimli@hotmail.com> created.**/#include <stdio.h>
#include <assert.h>
#include <stdlib.h>#ifndef TYPEDEF_H
#define TYPEDEF_Htypedef enum _Ret
{RET_OK,RET_OOM,RET_STOP,RET_INVALID_PARAMS,RET_FAIL
}Ret;typedef void (*DataDestroyFunc)(void* ctx, void* data);
typedef int (*DataCompareFunc)(void* ctx, void* data);
typedef Ret (*DataVisitFunc)(void* ctx, void* data);#ifdef __cplusplus
#define DECLS_BEGIN extern "C" {#define DECLS_END }
#else
#define DECLS_BEGIN
#define DECLS_END
#endif/*__cplusplus*/#define return_if_fail(p) if(!(p)) \{printf("%s:%d Warning: "#p" failed.\n", \__func__, __LINE__); return;}
#define return_val_if_fail(p, ret) if(!(p)) \{printf("%s:%d Warning: "#p" failed.\n",\__func__, __LINE__); return (ret);}#define SAFE_FREE(p) if(p != NULL) {free(p); p = NULL;}typedef Ret (*SortFunc)(void** array, size_t nr, DataCompareFunc cmp);#endif/*TYPEDEF_H*/
darray.h
/** File: darray.h* Author: Li XianJing <xianjimli@hotmail.com>* Brief: dynamic array implementation.** Copyright (c) Li XianJing** Licensed under the Academic Free License version 2.1** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*//** History:* ================================================================* 2009-01-02 Li XianJing <xianjimli@hotmail.com> created*/#include <stdio.h>
#include "typedef.h"#ifndef DARRAY_H
#define DARRAY_HDECLS_BEGINstruct _DArray;
typedef struct _DArray DArray;DArray* darray_create(DataDestroyFunc data_destroy, void* ctx);Ret darray_insert(DArray* thiz, size_t index, void* data);
Ret darray_prepend(DArray* thiz, void* data);
Ret darray_append(DArray* thiz, void* data);
Ret darray_delete(DArray* thiz, size_t index);
Ret darray_get_by_index(DArray* thiz, size_t index, void** data);
Ret darray_set_by_index(DArray* thiz, size_t index, void* data);
size_t darray_length(DArray* thiz);
int darray_find(DArray* thiz, DataCompareFunc cmp, void* ctx);
Ret darray_foreach(DArray* thiz, DataVisitFunc visit, void* ctx);void darray_destroy(DArray* thiz);DECLS_END#endif/*DARRAY_H*/
darray.c
/** File: darray.c* Author: Li XianJing <xianjimli@hotmail.com>* Brief: dynamic array implementation.** Copyright (c) Li XianJing** Licensed under the Academic Free License version 2.1** This program is free software; you can redistribute it and/or modify* it under the terms of the GNU General Public License as published by* the Free Software Foundation; either version 2 of the License, or* (at your option) any later version.** This program is distributed in the hope that it will be useful,* but WITHOUT ANY WARRANTY; without even the implied warranty of* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the* GNU General Public License for more details.** You should have received a copy of the GNU General Public License* along with this program; if not, write to the Free Software* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*//** History:* ================================================================* 2009-01-02 Li XianJing <xianjimli@hotmail.com> created**/#include <stdlib.h>
#include "darray.h"struct _DArray
{void** data;size_t size;size_t alloc_size;void* data_destroy_ctx;DataDestroyFunc data_destroy;
};static void darray_destroy_data(DArray* thiz, void* data)
{if(thiz->data_destroy != NULL){thiz->data_destroy(thiz->data_destroy_ctx, data);}return;
}DArray* darray_create(DataDestroyFunc data_destroy, void* ctx)
{DArray* thiz = malloc(sizeof(DArray));if(thiz != NULL){thiz->data = NULL;thiz->size = 0;thiz->alloc_size = 0;thiz->data_destroy = data_destroy;thiz->data_destroy_ctx = ctx;}return thiz;
}#define MIN_PRE_ALLOCATE_NR 10
static Ret darray_expand(DArray* thiz, size_t need)
{return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); if((thiz->size + need) > thiz->alloc_size){size_t alloc_size = thiz->alloc_size + (thiz->alloc_size>>1) + MIN_PRE_ALLOCATE_NR;void** data = (void**)realloc(thiz->data, sizeof(void*) * alloc_size);if(data != NULL){thiz->data = data;thiz->alloc_size = alloc_size;}}return ((thiz->size + need) <= thiz->alloc_size) ? RET_OK : RET_FAIL;
}static Ret darray_shrink(DArray* thiz)
{return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); if((thiz->size < (thiz->alloc_size >> 1)) && (thiz->alloc_size > MIN_PRE_ALLOCATE_NR)){size_t alloc_size = thiz->size + (thiz->size >> 1);void** data = (void**)realloc(thiz->data, sizeof(void*) * alloc_size);if(data != NULL){thiz->data = data;thiz->alloc_size = alloc_size;}}return RET_OK;
}Ret darray_insert(DArray* thiz, size_t index, void* data)
{Ret ret = RET_OOM;size_t cursor = index;return_val_if_fail(thiz != NULL, RET_INVALID_PARAMS); cursor = cursor < thiz->size ? cursor : thiz->size;if(darray_expand(thiz, 1) == RET_OK){size_t i = 0;for(i = thiz->size; i > cursor; i--){thiz->data[i] = thiz->data[i-1];}thiz->data[cursor] = data;thiz->size++;ret = RET_OK;}return ret;
}Ret darray_prepend(DArray* thiz, void* data)
{return darray_insert(thiz, 0, data);
}Ret darray_append(DArray* thiz, void* data)
{return darray_insert(thiz, -1, data);
}Ret darray_delete(DArray* thiz, size_t index)
{size_t i = 0;Ret ret = RET_OK;return_val_if_fail(thiz != NULL && thiz->size > index, RET_INVALID_PARAMS); darray_destroy_data(thiz, thiz->data[index]);for(i = index; (i+1) < thiz->size; i++){thiz->data[i] = thiz->data[i+1];}thiz->size--;darray_shrink(thiz);return RET_OK;
}Ret darray_get_by_index(DArray* thiz, size_t index, void** data)
{return_val_if_fail(thiz != NULL && data != NULL && index < thiz->size, RET_INVALID_PARAMS); *data = thiz->data[index];return RET_OK;
}Ret darray_set_by_index(DArray* thiz, size_t index, void* data)
{return_val_if_fail(thiz != NULL && index < thiz->size, RET_INVALID_PARAMS); thiz->data[index] = data;return RET_OK;
}size_t darray_length(DArray* thiz)
{size_t length = 0;return_val_if_fail(thiz != NULL, 0);return thiz->size;
}Ret darray_foreach(DArray* thiz, DataVisitFunc visit, void* ctx)
{size_t i = 0; Ret ret = RET_OK;return_val_if_fail(thiz != NULL && visit != NULL, RET_INVALID_PARAMS);for(i = 0; i < thiz->size; i++){ret = visit(ctx, thiz->data[i]);}return ret;
}int darray_find(DArray* thiz, DataCompareFunc cmp, void* ctx)
{size_t i = 0;return_val_if_fail(thiz != NULL && cmp != NULL, -1);for(i = 0; i < thiz->size; i++){if(cmp(ctx, thiz->data[i]) == 0){break;}}return i;
}void darray_destroy(DArray* thiz)
{size_t i = 0;if(thiz != NULL){for(i = 0; i < thiz->size; i++){darray_destroy_data(thiz, thiz->data[i]);}SAFE_FREE(thiz->data);SAFE_FREE(thiz);}return;
}#ifdef DARRAY_TEST#include <assert.h>static int int_cmp(void* ctx, void* data)
{return (int)data - (int)ctx;
}static Ret print_int(void* ctx, void* data)
{printf("%d ", (int)data);return RET_OK;
}static Ret check_and_dec_int(void* ctx, void* data)
{int* expected =(int*)ctx;assert(*expected == (int)data);(*expected)--;return RET_OK;
}static void test_int_darray(void)
{int i = 0;int n = 100;int data = 0;DArray* darray = darray_create(NULL, NULL);for(i = 0; i < n; i++){assert(darray_append(darray, (void*)i) == RET_OK);assert(darray_length(darray) == (i + 1));assert(darray_get_by_index(darray, i, (void**)&data) == RET_OK);assert(data == i);assert(darray_set_by_index(darray, i, (void*)(2*i)) == RET_OK);assert(darray_get_by_index(darray, i, (void**)&data) == RET_OK);assert(data == 2*i);assert(darray_set_by_index(darray, i, (void*)i) == RET_OK);assert(darray_find(darray, int_cmp, (void*)i) == i);}for(i = 0; i < n; i++){assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);assert(data == (i));assert(darray_length(darray) == (n-i));assert(darray_delete(darray, 0) == RET_OK);assert(darray_length(darray) == (n-i-1));if((i + 1) < n){assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);assert((int)data == (i+1));}}assert(darray_length(darray) == 0);for(i = 0; i < n; i++){assert(darray_prepend(darray, (void*)i) == RET_OK);assert(darray_length(darray) == (i + 1));assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);assert(data == i);assert(darray_set_by_index(darray, 0, (void*)(2*i)) == RET_OK);assert(darray_get_by_index(darray, 0, (void**)&data) == RET_OK);assert(data == 2*i);assert(darray_set_by_index(darray, 0, (void*)i) == RET_OK);}i = n - 1;assert(darray_foreach(darray, check_and_dec_int, &i) == RET_OK);darray_destroy(darray);return;
}static void test_invalid_params(void)
{printf("===========Warning is normal begin==============\n");assert(darray_length(NULL) == 0);assert(darray_prepend(NULL, 0) == RET_INVALID_PARAMS);assert(darray_append(NULL, 0) == RET_INVALID_PARAMS);assert(darray_delete(NULL, 0) == RET_INVALID_PARAMS);assert(darray_insert(NULL, 0, 0) == RET_INVALID_PARAMS);assert(darray_set_by_index(NULL, 0, 0) == RET_INVALID_PARAMS);assert(darray_get_by_index(NULL, 0, NULL) == RET_INVALID_PARAMS);assert(darray_find(NULL, NULL, NULL) < 0);assert(darray_foreach(NULL, NULL, NULL) == RET_INVALID_PARAMS);printf("===========Warning is normal end==============\n");return;
}static void single_thread_test(void)
{test_int_darray();test_invalid_params();return;
}int main(int argc, char* argv[])
{single_thread_test();return 0;
}
#endif
Makefile
CFILES=darray.c
all:gcc -g -shared -lpthread $(CFILES) -o libdarray.sogcc -g -DDARRAY_TEST -lpthread $(CFILES) -o darray_testclean:rm -f *test *.exe *.so
读书笔记 ——《系统程序员成长计划》篇7:动态数组相关推荐
- 读书笔记 ——《系统程序员成长计划》篇6:写的又快又好的秘诀
说明: 本文章旨在总结备份.方便以后查询,由于是个人总结,如有不对,欢迎指正:另外,内容大部分来自网络.书籍.和各类手册,如若侵权请告知,马上删帖致歉. QQ 群 号:513683159 [相 ...
- 读书笔记 ——《系统程序员成长计划》篇2:封装
说明: 本文章旨在总结备份.方便以后查询,由于是个人总结,如有不对,欢迎指正:另外,内容大部分来自网络.书籍.和各类手册,如若侵权请告知,马上删帖致歉. QQ 群 号:513683159 [相 ...
- 读书笔记 ——《系统程序员成长计划》篇3:双链表
说明: 本文章旨在总结备份.方便以后查询,由于是个人总结,如有不对,欢迎指正:另外,内容大部分来自网络.书籍.和各类手册,如若侵权请告知,马上删帖致歉. QQ 群 号:513683159 [相 ...
- 读书笔记 ——《系统程序员成长计划》篇1:代码风格
说明: 本文章旨在总结备份.方便以后查询,由于是个人总结,如有不对,欢迎指正:另外,内容大部分来自网络.书籍.和各类手册,如若侵权请告知,马上删帖致歉. QQ 群 号:513683159 [相 ...
- 读书笔记 ——《系统程序员成长计划》篇5:数据放在哪?
说明: 本文章旨在总结备份.方便以后查询,由于是个人总结,如有不对,欢迎指正:另外,内容大部分来自网络.书籍.和各类手册,如若侵权请告知,马上删帖致歉. QQ 群 号:513683159 [相 ...
- 啊哈c语言读后感500字,《麦田里的守望者》读后感读书笔记500字五篇
<<麦田里的守望者>读后感读书笔记500字五篇>由会员分享,可在线阅读,更多相关<<麦田里的守望者>读后感读书笔记500字五篇(5页珍藏版)>请在人人文 ...
- 系统程序员成长计划-管道过滤器(Pipe-And-Filter)模式
分享一下我老师大神的人工智能教程!零基础,通俗易懂!http://blog.csdn.net/jiangjunshow 也欢迎大家转载本篇文章.分享知识,造福人民,实现我们中华民族伟大复兴! 系统程序 ...
- 《系统程序员成长计划》成长过程
转载时请注明出处和作者联系方式 文章出处:http://www.limodev.cn/blog 作者联系方式:李先静 <xianjimli@gmail.com> <系统程序员成长计划 ...
- 系统程序员成长计划 ——学习篇7:排序算法
目标 前面完成了动态数组的实现,现在学习几种排序算法. 实现: ①冒泡排序②快速排序③归并排序 具体要求: ①同时支持升序排序和降序排序. ②同时支持多种数据类型. ...
最新文章
- 《深度学习:Java语言实现》一一2.6小结
- pandas使用dropna函数删除dataframe中列非缺失值的个数小于某一比例阈值的数据列
- 【原创】MIPS中断系统的板级验证及实例测试
- Sublime Text插件列表
- java精通时间_你真的精通 Java 吗?
- window7 修改docker安装的machine 位置
- Android中的onWindowFocusChanged()方法详解
- SqlDataReader循环取值
- 2010-2019年中国城市统计年鉴分享
- java 循环赛问题_分治法实现循环赛日程表问题
- 项目管理十大知识领域之项目质量管理
- 【5G核心网】 Network slicing 网络切片
- python 键盘输入负数_python输入负数
- FL Studio的音频录制插件Edison
- 深度学习中训练迭代次数理解【源码阅读技巧分享】【深度学习循环迭代理解】【for X, y in train_iter:】
- 如何通过Oracle官网下载jdk历史版本
- V2V迁移测试--VMware/VSphere环境迁移至KVM
- 阿里云服务器和腾讯云服务器哪个更好?多维度对比得出了结论
- 指数衰减函数c语言,使用Matlab实现对Ka波段卫星通信衰减 信道的性能仿真
- odb++ DEMO