您的位置:首页 > 理论基础 > 数据结构算法

数组的理解与实现[数据结构]

2016-01-26 12:40 639 查看

一、概述

相信大家对数组都不会太陌生,C、C++、Java、PHP等高级语言中,都有数组这个概念。

数组是一种线性结构,也属于比较简单的一种结构。但是简单的东西往往意味着使用广泛。

数组在各大语言中都有所涉及,是很重要的一种数据结构。

掌握数组,可以使我们对编程有另一个角度的理解,有助于我们合理的使用数组,使代码“更上一层楼”。

下面,我们就用C语言来实现数组吧!

二、数组的实现

建议:程序用到了C语言中“指针“、”结构体“、”malloc()“的知识,请先学习这部分知识,否则下面代码看起来很晕。。。

1、首先,我们先将能够表示数组的结构建立出来

typedef struct Arr
{
int length;   //数组长度
int *pBase;  //指向数组第1个元素的指针
int cnt;     //数组的有效长度

}ARR,*PARR;      //PARR为指向变量ARR类型的指针


程序意义如下图:



2、我们初始化一个数组

//初始化数组
void initArr(PARR pArr,int length)
{
pArr->pBase=(int *)malloc(sizeof(int)*length);
if(pArr->pBase==NULL)
{
printf("数组初始化失败\n");
exit(-1);
}
else
{
pArr->length=length;
pArr->cnt=0;
}
}


如果初始化成功,会如下图(我们假设length=3):



3、在末尾追加元素

//追加元素,int val为插入的值
void appendArr(PARR pArr,int val)
{
if(isFull(pArr))//isFull()是判断数组是否已满的函数,这里先不用管
{
printf("数组已满。不可追加元素!\n");
}
else
{
pArr->pBase[pArr->cnt]=val;
pArr->cnt++;
}
}


假设我们调用此函数,追加2和4到数组。如下图:



4、在任意位置插入一个元素

//插入元素,val为要插入的值,pos为插入的位置
void insertArr(PARR pArr,int val,int pos)
{
if(isFull(pArr))
{
printf("数组已满,不可插入元素\n");
}
else
{
int i;
for(i=pArr->cnt;i>=pos;i--)
{
pArr->pBase[i]=pArr->pBase[i-1];
}
pArr->pBase[pos-1]=val;
pArr->cnt++;
}
}


比如:我在 1 位置插入 数值 6,那么就像下图了:



for(i=pArr->cnt;i>=pos;i--)
{
pArr->pBase[i]=pArr->pBase[i-1];
}


上面这段代码可能不太好理解,以上面数组为例讲解

未插入元素前,数组含有元素2、4,数组的cnt(有效长度)位2。

要想插入元素,那么2、4元素都要向后移动一个位置,

当然先从4开始移动(从2开始移动的话,2会覆盖掉4)

上面代码就是说,先从最后一位(4)开始向后依次移动,空出第1个位置来。

如图:



5、遍历数组

//遍历数组
void showArr(PARR pArr)
{
if(isEmpty(pArr))
{
printf("数组为空!\n");
}
else
{
int i;
for(i=0;i<pArr->cnt;i++)
{
printf("%d ",pArr->pBase[i]);
}
}
}


遍历数组比较简单,这里就不详细讲解了,但要注意:

*(a+i)==a[i](a是指向数组 起始位置的指针)相当于这里的

*(pArr->pBase + i)==pArr->pBase[i]

6、删除任意位置的元素

//删除任意位置的元素
void deleteArr(PARR pArr,int pos)
{
if(isEmpty(pArr))
{
printf("数组为空,不可删除\n");
}
else
{
int i;
for(i=pos;i<pArr->cnt;i++)
{
pArr->pBase[i-1]=pArr->pBase[i];
}
pArr->cnt--;
}
}


上面的核心代码为:

for(i=pos;i<pArr->cnt;i++)
{
pArr->pBase[i-1]=pArr->pBase[i];
}


以以上数组讲解此代码:

数组原有3个元素6、2、4,假设我们要删除第1个位置的元素

那么,2就向前移动一个位置(2→覆盖→6),

接下来,4再向前移动一个位置(4→覆盖→2)。

上面代码就是实现了覆盖的一个功能,如图:



三、总体实现代码

#include <stdio.h>
#include <stdlib.h>
typedef struct Arr
{
int length; //数组长度
int *pBase; //指向数组第1个元素的指针
int cnt; //数组的有效长度

}ARR,*PARR; //PARR为指向变量ARR类型的指针

//初始化数组 void initArr(PARR pArr,int length) { pArr->pBase=(int *)malloc(sizeof(int)*length); if(pArr->pBase==NULL) { printf("数组初始化失败\n"); exit(-1); } else { pArr->length=length; pArr->cnt=0; } }
//判断数组是否已满
int isFull(PARR pArr)
{
if(pArr->length==pArr->cnt)
{
return 1;
}
else
{
return 0;
}
}
//追加元素
void appendArr(PARR pArr,int val)
{
if(isFull(pArr))
{
printf("数组已满。不可追加元素!\n");
}
else
{
pArr->pBase[pArr->cnt]=val;
pArr->cnt++;
}
}
//插入元素
void insertArr(PARR pArr,int val,int pos)
{
if(isFull(pArr))
{
printf("数组已满,不可插入元素\n");
}
else
{
int i;
for(i=pArr->cnt;i>=pos;i--) { pArr->pBase[i]=pArr->pBase[i-1]; }pArr->pBase[pos-1]=val;
pArr->cnt++;
}
}
//判断数组是否为空
int isEmpty(PARR pArr)
{
if(pArr->cnt==0)
{
return 1;
}
else
{
return 0;
}
}
//遍历数组 void showArr(PARR pArr) { if(isEmpty(pArr)) { printf("数组为空!\n"); } else { int i; for(i=0;i<pArr->cnt;i++) { printf("%d ",pArr->pBase[i]); } } }//删除任意位置的元素 void deleteArr(PARR pArr,int pos) { if(isEmpty(pArr)) { printf("数组为空,不可删除\n"); } else { int i; for(i=pos;i<pArr->cnt;i++) { pArr->pBase[i-1]=pArr->pBase[i]; } pArr->cnt--; } }//主函数
int main()
{
ARR arr;
int length=3;
initArr(&arr,length);
appendArr(&arr,2);
appendArr(&arr,4);
insertArr(&arr,6,1);
deleteArr(&arr,1);
showArr(&arr);
return 0;
}


四、数组的优缺点

由以上对数组的实现可知:

数组的遍历、以及取出某个位置的元素非常快,因为数组是连续的

但是要想在任意位置 插入、删除 元素确很慢,需要大动干戈。

比如数组一共有10个位置,现在要在2位置插入一个元素,那么3-9位置的元素都得向后移动,非常耗时间。

所以,总结优缺点:

优点:查找快速、相对链表占用空间少

缺点:插入、删除很慢,并且需要连续的大块空间来存储数据。

以上就是关于数组的简单讲解,本人也是初学,很多问题不甚明了,讲解的不够透彻。

如有错误之处,敬请不吝指正。

如有不明之处,欢迎相互探讨。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  数据结构