【算法】C语言实现数组的动态分配
C语言实现数组的动态分配
作者:白宁超
2016年10月27日20:13:13
摘要:数据结构和算法对于编程的意义不言而喻,具有指导意义的。无论从事算法优化方向研究,还是大数据处理,亦或者网站开发APP开发云云。在求职过程中数据结构必然也是笔试的重点,面试的常客。基于此,系统梳理复习下数据结构和算法相关知识,其实核心为链表操作,串的匹配,树的先序、中序、后序。排序的相关操作,查找相关操作,深度优先遍历、广度优先遍历、哈弗曼树、动态规划等。本节为开胃菜,数组的相关操作(本文原创编著,转载注明出处:C语言实现数组的动态分配)
1 数组动态分配思想
数组是最常用的数据结构,在内存中连续存储,可以静态初始化(int a[2]={1,2}),可以动态初始化 malloc()。难点就是数组在删除或者插入元素的时候,要移动元素的坐标不好确定。规律:
1.如果要在数组中第pos个位置插入一个元素(应该从后面开始移动)
for( i=cnu;i>=pos;i--) pBase[i]=pBase[i-1];
2.删除数组第pos位置的元素
for(i=pos+1;i<=cnu;i--) pBase[i-2]=pBase[i-1];
使用malloc动态分配内存并将返回值赋给整形指针
int pBase=(int *)malloc(sizeof(int)len);//分配4*len字节长度的内存
这是pBase可以指向数组中的第一个元素,可以作为数组变量名称使用。
2 数组的优缺点
优点:
存取速度快 o(1) 可以直接根据下标找到内存位置
缺点:
- 事先必须知道数组的长度
- 插入删除元素很慢
- 空间通常是有限制的
- 需要大块连续的内存块
- 插入删除元素的效率很低
3 完整案例
#include<stdio.h> #include<malloc.h> #include<stdbool.h> /* 定义结构体 */ struct Arr{ int len;//数组能存取的最大元素个数 int cnu;//数组中当前元素个数 int *pBase;//存储指向数组的指针 }; /*初始化数组*/ void init_Arr(struct Arr *pArray,int len){ pArray->pBase=(int*)malloc(sizeof(int)*len);//分配4*len字节长度的内存 if(NULL== pArray->pBase){ printf("动态分配内存失败\n"); }else{ pArray->len=len; pArray->cnu=0; printf("动态分配内存成功 %d \n",pArray->len); } } /*判断数组是否为空,传地址省内存4字节,传结构体变量需要进行拷贝,12字节*/ bool isempty(struct Arr *pArray){ if(0==pArray->cnu) return true; else return false; } /*判断数组是否满了*/ bool isfull(struct Arr *pArray){ if(pArray->len==pArray->cnu) return true; else return false; } /*显示数组内容*/ void show_Arr(struct Arr *pArray){ if(isempty(pArray)) printf("数组为空!\n"); else{ for(int i=0; i<pArray->cnu;i++){ printf("%d \t\t %d \t\t %d \n",pArray->pBase[i],pArray->cnu,pArray->len); } printf("------------------------------------\n"); } } /*向数组追加元素*/ bool append(struct Arr *pArray,int val){ if(isfull(pArray)){ printf("数组已经满了!\n"); return false; }else{ pArray->pBase[pArray->cnu]=val; pArray->cnu++; } } /*向数组中插入元素,pos为数组中第几个位置,pos=3就是向a[2]插入元素*/ bool insert(struct Arr *pArray,int pos,int val){ if(pos<1||pos>pArray->len+1){ printf("插入的位置输入的不合法\n"); return false; } if(isfull(pArray)){ printf("数组已经满了,插入失败!\n"); return false; } else{ //printf("数组 %d \n",pArray->cnu); for(int i=pArray->cnu;i>=pos;i--){//循环将pos位置开始的数组后移 pArray->pBase[i]=pArray->pBase[i-1]; } pArray->pBase[pos-1]=val; pArray->cnu++; pArray->len++; return true; } } /*删除数组中的第pos个元素,同时返回删除的元素的值*/ bool delete(struct Arr *pArray,int pos,int *val){ if(pos<1||pos>pArray->cnu){ printf("删除失败,位置不合法\n"); return false; } if(isempty(pArray)){ printf("数组已经空,删除失败!\n"); return false; } else{ *val=pArray->pBase[pos-1]; for(int i=pos+1;i<=pArray->cnu;i++){ pArray->pBase[i-2]=pArray->pBase[i-1]; } pArray->cnu--; return true; } } /*数组倒置*/ bool inverse(struct Arr *pArray){ if(isempty(pArray)){ printf("倒置失败,因数组为空"); return false; } else{ int i=0,j=pArray->cnu-1,temp; while(i<j){ temp=pArray->pBase[i]; pArray->pBase[i]=pArray->pBase[j]; pArray->pBase[j]=temp; i++; j--; } } return true; } int main(){ struct Arr arr; init_Arr(&arr,20); append(&arr,1); append(&arr,2); append(&arr,3); append(&arr,4); append(&arr,5); show_Arr(&arr); insert(&arr,2,88); show_Arr(&arr); int val; delete(&arr,1,&val); show_Arr(&arr); printf("删除了 %d\n",val); inverse(&arr); show_Arr(&arr); return 0; }
4 运行结果
Success time: 0 memory: 2300 signal:0
动态分配内存成功 20 1 5 20 2 5 20 3 5 20 4 5 20 5 5 20 ------------------------------------ 1 6 21 88 6 21 2 6 21 3 6 21 4 6 21 5 6 21 ------------------------------------ 88 5 21 2 5 21 3 5 21 4 5 21 5 5 21 ------------------------------------ 删除了 1 5 5 21 4 5 21 3 5 21 2 5 21 88 5 21 ------------------------------------
5 实例解析
结构体:结构体(struct)指的是一种数据结构,是C语言中聚合数据类型的一类。 结构体可以被声明为变量、指针或数组等,用以实现较复杂的数据结构。结构体的定义如下所示,
struct tag { member-list } variable-list ;
struct为结构体关键字,tag为结构体的标志,member-list为结构体成员列表,其必须列出其所有成员;variable-list为此结构体声明的变量。
思路:
- 创建结构体记得关键字struct
- 花括号内创建结构体属性
例如:
/* 定义结构体 */ struct Arr{ int len;//数组能存取的最大元素个数 int cnu;//数组中当前元素个数 int *pBase;//存储指向数组的指针 };
初始化数组:
思路:
- 创建初始化函数,给数组分配长度malloc(sizeof(int)*len
- 指针地址为空,分配内存失败
- 反之,数组长度为当前内存长度,数组当前位置为0
例如:
/*初始化数组*/ void init_Arr(struct Arr *pArray,int len){ pArray->pBase=(int*)malloc(sizeof(int)*len);//分配4*len字节长度的内存 if(NULL== pArray->pBase){ printf("动态分配内存失败\n"); }else{ pArray->len=len; pArray->cnu=0; printf("动态分配内存成功 %d \n",pArray->len); } }
判断数组是否为空:
- 创建判空函数,结构体参数数组
- 判断当前元素个数是否为空
/*判断数组是否为空,传地址省内存4字节,传结构体变量需要进行拷贝,12字节*/ bool isempty(struct Arr *pArray){ if(0==pArray->cnu) return true; else return false; }
判断数组是否为满:
- 创建判满函数,结构体参数数组
- 判断数组长度是否为当前元素长度
例如:
/*判断数组是否满了*/ bool isfull(struct Arr *pArray){ if(pArray->len==pArray->cnu) return true; else return false; }
向数组追加元素:
- 创建追加函数,结构体数组参数,元素值
- 注意判满情况,反之循环输入
- 数组当前指针地址赋值
- 数组指向下一个位置,自加
例如:
/*向数组追加元素*/ bool append(struct Arr *pArray,int val){ if(isfull(pArray)){ printf("数组已经满了!\n"); return false; }else{ pArray->pBase[pArray->cnu]=val; pArray->cnu++; } }
显示数组内容
- 创建显示函数,结构体数组参数
- 注意判空情况,反之循环输入
- 遍历数组输出
例如:
/*显示数组内容*/ void show_Arr(struct Arr *pArray){ if(isempty(pArray)) printf("数组为空!\n"); else{ for(int i=0; i<pArray->cnu;i++){ printf("%d \t\t %d \t\t %d \n",pArray->pBase[i],pArray->cnu,pArray->len); } printf("------------------------------------\n"); } }
向数组中插入元素:pos为数组中第几个位置,pos=3就是向a[2]插入元素
- 创建插入函数,结构体数组参数,位置参数,插入值参数
- 判断插入位置是否越界,判断数组是否满
- 循环将pos位置开始的数组后移,移动范围是从第pos个到第cnu个
- 循环将pos位置开始的数组后移,将值插入pos处
- 指向下一位且长度加1
例如:
/*向数组中插入元素,pos为数组中第几个位置,pos=3就是向a[2]插入元素*/ bool insert(struct Arr *pArray,int pos,int val){ if(pos<1||pos>pArray->len+1){ printf("插入的位置输入的不合法\n"); return false; } if(isfull(pArray)){ printf("数组已经满了,插入失败!\n"); return false; } else{ //printf("数组 %d \n",pArray->cnu); for(int i=pArray->cnu;i>=pos;i--){//循环将pos位置开始的数组后移 pArray->pBase[i]=pArray->pBase[i-1]; } pArray->pBase[pos-1]=val; pArray->cnu++; pArray->len++; return true; } }
删除数组中的第pos个元素:同时返回删除的元素的值
- 创建插入函数,结构体数组参数,位置参数,插入值参数
- 判断插入位置是否越界合法
- 获取删除的元素值
- 移动单位是从第pos+1个到cnu
- 指针向前指向,自减
例如:
/*删除数组中的第pos个元素,同时返回删除的元素的值*/ bool delete(struct Arr *pArray,int pos,int *val){ if(pos<1||pos>pArray->cnu){ printf("删除失败,位置不合法\n"); return false; } if(isempty(pArray)){ printf("数组已经空,删除失败!\n"); return false; } else{ *val=pArray->pBase[pos-1]; for(int i=pos+1;i<=pArray->cnu;i++){ pArray->pBase[i-2]=pArray->pBase[i-1]; } pArray->cnu--; return true; } }
数组倒置
- 创建倒置函数,判断数组是否为空
- 三个变量进行交换,其中temp中间变量,ij分别指向数组首尾索引
- 循环数组,使前后索引交换位置
- 每一遍循环,ij索引分别前进一步,直到跳出循环,程序结束
例如:
/*数组倒置*/ bool inverse(struct Arr *pArray){ if(isempty(pArray)){ printf("倒置失败,因数组为空"); return false; } else{ int i=0,j=pArray->cnu-1,temp; while(i<j){ temp=pArray->pBase[i]; pArray->pBase[i]=pArray->pBase[j]; pArray->pBase[j]=temp; i++; j--; } } return true; }
作者:白宁超,工学硕士,现工作于四川省计算机研究院,研究方向是自然语言处理和机器学习。曾参与国家自然基金项目和四川省科技支撑计划等多个省级项目。著有《自然语言处理理论与实战》一书。 自然语言处理与机器学习技术交流群号:436303759 。
出处:http://www.cnblogs.com/baiboy/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。