**
为什么要提出动态数组
**
我们知道,内存中的存储单元是连续分布的,这就导致我们想要存储一个100MB的数据的时候,我们要分配一个100MB个连续的地址去存储这组数据。但是这样会产生一些问题,首先最困扰我们的就是,我们想要存储一个数据,就要首先告诉系统,我要用存储多少什么样类型的数据,我要申请多少的空间去存储这些数据。但是我们往往存储的数据随着时间的增长,数据也是往往也会增长。一开始申请的数据的空间就变的不够了,我们还用重新的申请更多的数据空间,但是后面的空间也可能被其他数据给占用了。这样静态的数据存储给我们带来了一些不方便。我们希望有一种动态的方式去存储我们的数据,就是我们不预先告诉电脑我们要多少空间,而是随着我们数据的增长,存储空间也会自动的增长。
动态存储的两种方法的分析
方法一:利用数组进行存储。数组是在一个连续的数据空间中存储数据,比如一个数列[1,3,4,5,6]。在数组中他们的数据所存在的地址是连续的。比如1在内存地址1中,那么它后面的3在内存地址2中。我们可以通过计算来找到目标地址,想查找某一个位置数据的时候,我们可以直接去访问,方便随机访问。但是,因为位置是相连的,所以我们要在这个数组中插入一个数据的时候。我们需要把插入的这个数据的空间留出来。那么就需要把插入位置后面的数据在从后往前依次的向后移动。来留出空间存储插入数据。而我们删除某一数据的时候,我们同样要把后面的数据向前移动,来把空出来的位置补上。保证数据存储的连续性。所以数组的有以下的缺点1、对内存的要求高,必须要连续的内存空间;2、插入和删除的效率比较低;
3、数组大小固定,动态拓展性差,而且可能浪费内存;。但是列表也有以下的有点:随机访问性强,查找速度快。
方法二:利用链表进行存储。链表和数组不同,什么是链表呢?链表并不要求存储空间是连续的。那么它是怎么寻找其它数据的呢?链表中单个数据,里面存储的分为两个部分,一个是数据本身,另一个则是下一个数据存储的地址。因为链表存储数据不是连续的,下一个数据存在哪里是随机的,这样就不要求我们分配一个连续的空间去存放一组数据了,用零散的空间就可以存储一组数据。但是我们不能根据第一个数据的位置来计算出来接下来数据存储的位置,这就需要将下一个位置存储下来。使得我们下次能够查找到。链表的优点1、对内存的要求低,大小可以不固定,内存的利用率比较高2、插入和删除方便。存在的缺点是:查找效率低,不可以随机查找,每次查找必须从头开始。
JAVA中的实现方式
一丶链表的动态存储实现:
我们要实现存储功能中最基础的增删查改:
首先我们要定义节点类
public class Node {
public Object obj;
public Node node;
/*定义中 obj 是存储我们需要存储的数据的,这里使用Object
使得Node中可以存储任意的数据类型
*/
public Node(Object obj){
this.obj = obj;
}
}
接着我们实现增删查改的功能
//规定一个泛型<L>,让数组中存储的是同一类的数据;
public class ArryList<L> {
//定义头节点和尾节点,头节点存储第一个元素。
//在又了头节点我们就可以访问链表中任何一个元素了
//尾节点存储最后一个元素
private Node head;
private Node tail;
int len = 0;
@Override
//向链表中增加节点
public void add(L l) {
// TODO Auto-generated method stub
Node newnode = new Node(l);
if (head == null) {
head = newnode;
len++;
}
else {
if(tail == null) {
tail = newnode;
head.node = tail;
len ++;
}
else{
tail.node = newnode;
tail = newnode;
len++;
}
}
}
//查找第i给位置的数据
@Override
public L Geti(int i) {
// TODO Auto-generated method stub
if(i<= len) {
Node newnode = head;
for(int j = 1; j < i; j++) {
newnode = newnode.node;
}
return (L)newnode.obj;
}
return null;
}
//删除第i个位置的数据
//只需要将第i-1位置中存储下一个节点位置的值换成第i+1个节点位置的值
@Override
public void Remove(int i) {
// TODO Auto-generated method stub
if(i > len) {
System.out.println("err:超出索引范围");
return;
}
if(i==1) {
head = head.node;
len--;
}
else {
Node newnode = head;
for(int j = 1; j < i - 1; j++) {
newnode = newnode.node;
}
if(i == len) {
tail = newnode;
len--;
}
else {
newnode.node = newnode.node.node;
len--;
}
}
}
//替换第i个节点的数据
@Override
public void Repalce(int i, L Data) {
// TODO Auto-generated method stub
if(i<len) {
Node newnode = head;
for(int j = 1; j < i; j++) {
newnode = newnode.node;
}
newnode.obj = Data;
}else{
System.out.println("err:超出索引范围");
}
}
//找出第i个节点中所有的信息
public Node FindNode(int i) {
if(i > len){
System.out.println("err:超出索引范围");
return ;
}
Node newnode = head;
for(int j = 1; j < i; j++) {
newnode = newnode.node;
}
return newnode;
}
public int getsize() {
return len;
}
}
二丶数组的动态存储实现:
我们接下来简单模拟一下数组的动态存储的实现代码。我们在上面提到了,静态数组是要开始的时候定义大小的。动态的就是在静态的基础上,动态的为静态数组重新分配大小。我们先建立一个能存10个数据的数组,当存储的数据数量大于10 的时候,我们就在定义一个能存储20个数的新数组。让后将原来存储10个数据的数组中的10个数据,按顺序迁移到新数组中。然后再继续存储。当不够的时候我们再建立一个容量是现在数组一倍的新数组。依次类推。
当我们删除数据的时候,数据剩余的数量不足现在数组容量的一半的时候,我们就建立一个,容量是现在一个数组一半的新数组,再将数组迁移过去。以此类推,这样可以缓解空间浪费的弊端。
public class arrylist<L> {
private int sizelong = 0;
private int number = 10;
private Object arry[] = new Object[number];
private int indx = 0;
//增加元素
public void add(L a) {
if (indx > number - 1){
int newnumber = number * 2;
Object newarry[] = new Object[newnumber];
for(int i = 0;i<number - 1;i++) {
newarry[i] = arry[i];
}
arry = newarry;
number = newnumber;
}
arry[indx] = a;
indx ++;
sizelong = sizelong + 1;
System.out.println(indx);
}
public int size(){
return sizelong;
}
//弹出第i的数据
public Object pop(int i) {
if(i > sizelong) {
return null;
}
else{
Object num = arry[i - 1];
toremove(i);
return num;
}
}
//删除位置j的数据
public void remove(int j) {
if(j > sizelong) {
}
else {
toremove(j);
}
}
//删除第i个位置元素的方法
private void toremove(int site) {
sizelong = sizelong - 1;
int half = number / 2;
if (sizelong >= half) {
for (int i = site;i<=sizelong;i++) {
arry[i-1]=arry[i];
}
}
else {
int newnumber = number / 2;
Object newarry[] = new Object[newnumber];
for (int i = 0;i<site-1;i++) {
newarry[i] = arry[i];
}
for(int j = site;j<=sizelong;j++) {
newarry[j - 1] = arry[j];
arry = newarry;
}
}
indx = indx - 1;
}
public Object[] getarry() {
return arry;
}
}