当数据结构遇到编程语言——数组

赵振江 数据结构 数组 一维数组

“数组”你真的很了解吗?

数组大家都不是很陌生,它已经“植入”了许多编程语言,但初学者一提到数组,可能不会联想到“数据结构”,而是想到的会是一种“数据类型”,数组本质上就是一种极其简单的数据结构。所谓数组,就是相同数据类型的元素按一定顺序排列的集合。也就是在内存中划分一段连续的且大小固定(注意是连续)的内存空间(或者其他存储器)保存相同数据类型的数据,如下图。一般说的简单数组,都是静态的数组,所以很容易导致数据溢出和访问越界。不需担心的是,很多高级语言中已经设计了动态数组了,这个以后还会讨论。

数组的维数

数组的维数始终是个重要话题,这里先看看最简单的一维数组。对了,搞数学的更愿意把二维数组称之为“矩阵”,关于矩阵的话题也很多,以后会提到。依次类推还有三维、四维、……

数组和表有什么关系

先说明一下:数组属于线性表。关于表的话题以后再说,不急。

数组和数据类型

int型的数组、float型的数组好理解,也就是规定数组里面存储了统一数据类型的变量(绝大部分编程语言都是这样,有些不一定如:Visual Foxpro)。在C/C++中,数组是基本数据类型,C中作为一种构造数据类型出现,而在java中作为引用数据类型出现(有的书也称之为 对象数据类型)。

数组与Java,C++,C,JS,汇编……(之后再补充)

知道了数组的数据组织方式(在内存中的结构),接下来就要知道对于数组的一些操作(处理)了。主要就是插入insert,查找find,删除remove,显示。这里分别用几种编程语言来实现,显然java和C++等具有面向对象编程思想的编程语言,对于实现算法要直观些,但要讲到对于在数组内存中的体现,显然C和汇编直观些。

Java语言版本

class Array{

    private long[] a;

    int nElems;

    //构造函数constructor
    public Array(int size){
        this.a=new long[size];
        this.nElems=0;
    }

    //插入insert
    public void insert(long e){
        a[nElems]=e;
        nElems++;
    }

    //查找find
    public int find(long searchKey){
        int j;
        for(j=0;j<nElems;j++){
            if(searchKey==a[j])
                return j;
        }
        return -1;
    }

    //删除delete
    public boolean remove(long searchKey){
        int k =find(searchKey);
        if(k!=-1){
            for(;k<nElems;k++){
                a[k]=a[k+1];
            }
            nElems--;
            return true;
        }
        return false;
    }

    //显示display
    public void display(){
        for(int i =0;i<nElems;i++){
            System.out.print(a[i]+" ");
        }
    }
}

public class ArrayTest {
    public static void main(String[] args){
        Array array = new Array(10);
        //插入
        array.insert(12);
        array.insert(13);
        array.insert(11);
        array.insert(15);
        array.insert(16);
        //查找
        if(array.find(13)!=-1)
            System.out.println("查找成功,下标为:"+array.find(13));
        else System.out.println("查找失败!");
        //删除
        if(array.remove(11))
            System.out.println("删除成功!");
        else System.out.println(" 删除失败!");
        //显示
        System.out.print("显示数组:");
        array.display();
    }

}

C++语言版本

#include <iostream>
using namespace std;

template <class T>
class Array{
private :
    int size;               //数组大小
    T *a;               //一维数组
    int nElems;             //实际元素个数
public:
    Array(int sz);              //构造函数
    ~Array() {delete [] a;}            //析构函数
    int Size(){             //返回数组大小
        return size;
    }
    void insert(T e);               //插入

    int find(T e);              //查找

    bool remove(T e);               //删除

    void display();

};
template <class T>
Array<T>::Array(int sz){
    if(sz<0){
        cerr<< "数组元素不能为0"<<endl;
        return;
    }
    else{
        size=sz;
        a= new T[sz];
        nElems=0;
    }

}

/////////插入/////////////
template <class T>
void Array<T>:: insert(T e){
    a[nElems]=e;
    nElems++;
}

//////////查找///////////////
template <class T>
int Array<T>::find(T searchKey){
    int j;
    for(j=0;j<nElems;j++){
        if(searchKey==a[j])
            return j;
    }
    return -1;
}

///////////删除///////////
template <class T>
bool Array<T>::remove(T e){
    int k =find(e);
    if(k!=-1){
        for(;k<nElems;k++){
            a[k]=a[k+1];
        }
        nElems--;
        return true;
    }
    return false;
}

//////////显示//////////////
template <class T>
void Array<T>::display(){
    for(int i =0;i<nElems;i++){
        cout<<a[i]<<" ";
    }
}

int main() {
    Array<long> arr(10);
    //插入
    arr.insert(12);
    arr.insert(13);
    arr.insert(14);
    arr.insert(15);
    arr.insert(16);
    //显示
    arr.display();
    cout<<endl;
    //查找
    cout<<arr.find(13)<<endl;               //注意返回的是下标
    //删除
    arr.remove(14);
    //显示
    arr.display();
    ~Array();
    return 0;
}

JS语言版本

//稍等两天提供

C语言版本

具体操作这里不再提供,只提供struct结构体,构造数组和销毁数组函数

#include <stdio.h>
#include <stdlib.h>

#define OK 1
#define ERROR 0
#define ElemType int
#define Status int
#define OVERFLOW 3
//定义结构体Array
typedef struct{
    ElemType *base;
    int nElems;
    int size;
}Array;

//初始化数组,类似于java和C++的构造函数
Status InitArray(Array A,int sz){
    A.size=sz;
    if(sz<0)
        return ERROR;
    A.base=(ElemType *)malloc(A.size*sizeof(ElemType));
    if(!A.base) exit(OVERFLOW);
    return OK;
}

//销毁数组,类似C++的析构函数和java的垃圾回收
Status DestroyArray(Array A){
    if(!A.base)
        return ERROR;
    free(A.base);
    A.base=NULL;
    return OK;
}

Win32汇编版本

汇编版本的更加直观,所谓直观,是直接到了内存的层面。程序先是以Array为基地址,连续创建了4块每块大小为32bit(4字节,双字)连续的空间,并进行了初始赋值。下面用提示框(MessageBox)进行数组的展示,和数组大小的展示(用lengthof可以更快实现,程序中都有用到)。接着用一个loop循环,依次遍历读取数组各个元素,算出数组元素的和。其中部分注释展示了,数组的读取和删除,注意删除的时候,数组后面元素会向前移动,这在上面的Java 和C++中有所展示,汇编里就不再展示了。

.386
.model flat,stdcall
option casemap:none

include user32.inc
include windows.inc
includelib user32.lib
include kernel32.inc
includelib kernel32.lib

.data
Array DWORD 12,23,11,22     ;Array为基地址,数据类型为双字(32bit,4个字节)
ArraySize=($-Array)/4
szCap db ‘一维数组‘,0
szText1 db 100 dup(0)           ;100byte字符缓冲区
szText2 db 100 dup(0)
szOutPut1 db ‘数组:%d,%d,%d,%d 长度:%d‘,0
szOutPut2 db ‘数组:%d‘,0
.code
start:
invoke wsprintf,addr szText1,addr szOutPut1,Array,Array+4,Array+8,Array+12, ArraySize
invoke MessageBox,NULL,offset szText1,offset szCap,MB_OK
mov esi,offset Array
mov ecx,lengthof Array
L:                          ;循环读取数组元素,并求所有元素之和
add eax,[esi]
add esi,type Array          ;指向下一个元素
loop L

;mov eax,[esi+4]        ;数组第2个元素
;mov [esi+8],[esi+12]       ;删除数组第三个元素
invoke wsprintf,addr szText2,addr szOutPut2,eax
invoke MessageBox,NULL,addr szText2,offset szCap,MB_OK
invoke ExitProcess,NULL
end start

数组存放对象元素

以上无论是什么语言的数组,里面存储的元素都是基本数据类型的,这显然不符合平时的需求,我们希望它可以存储对象元素(当然,得是遵循OOP的编程语言)。这里以java为例,用数组来存放Person类类型的数据。

package array;
/**
 *
 * @author River 2015-1-27
 *
 */

/**
 * Person类
 */
class Person{
    private long ID;
    private String name;
    private int age;

    public Person(long id,String n,int a){
        ID=id;
        name=n;
        age=a;
    }
    public String display(){
        return "id:"+ID+" 姓名:"+name+"  年龄:"+age;
    }

    public String getName(){
        return name;
    }

    public long getID(){
        return ID;
    }
}

/**
 * ClassDataArray类实现,数组保存对象
 * @author River
 *
 */
class ClassDataArray{
    private Person[] a;             //定义一个Person类型的数组
    private int nElems;             //实际元素个数

    public ClassDataArray(int size){
        a=new Person[size];
        nElems=0;
    }

    ////////////插入/////////////////
    //public void insert(Person per){
    public void insert(long id,String name,int age){
        a[nElems]= new Person(id, name, age);
        nElems++;
    }

    ////////////查找//////////////////

    public int find(long id){
        for(int j=0;j<nElems;j++){
            if(a[j].getID()==id)
                return j;               //找到,返回下标
            else if(j==nElems)
                break;                  //没有查找到
        }
        return nElems;
    }
    ///////////查找另一种写法////////////
    /*public Person find2(String name){
        for(int j=0;j<nElems;j++){
            if(a[j].getName().equals(name))
                return a[j];                //找到,返回下标
            else if(j==nElems)
                break;                  //没有查找到
        }
        return null;
    }*/

    //////////////删除//////////////
    public boolean delete(long id){
        if(find(id)!=nElems){
            for(int j=find(id);j<nElems;j++)
                a[j]=a[j+1];
            nElems--;
            return true;
        }
        return false;
    }

    ///////////////显示/////////////////
    public void display(){
        for(int j=0;j<nElems;j++){
            System.out.println(a[j].display());
        }
    }
}
public class ClassDataArrayTest {
    public static void main(String[] args){
        ClassDataArray arr = new ClassDataArray(10);
        arr.insert(1, "River", 22);
        arr.insert(2, "ShiTianShaoNv", 22);
        arr.insert(3, "QiXiaoXing", 21);

        arr.display();

        arr.find(1);//可以写成查找名字的形式
        arr.delete(2);
        arr.display();
    }

}

数组真的是存储的对象?

数组确实存储的是对象元素,但可能与你心中想象的有些区别,这时,数组实际存储的是一个地址,这个地址指向目标对象在里面的首地址,而这个变量名(对象名),存在于栈当中。

数组的优点与缺点

优点:数据结构简单,可以完成简单的数据存储。当对于数据元素没有要求时(比如顺序),可以很容易的进行数据添加(在数组尾部插入即可)。

缺点:数组的大小尺寸是不变的,太小容易越界,太大浪费空间。查找,添加,删除都比较费时(除去最好情况),移动数组元素比较频繁。具体的复杂度这里先不给出,下篇专门讨论复杂度问题。

数组的升级版

有序数组,放到算法分析里以其例子进行说明。

时间: 2024-10-12 21:40:55

当数据结构遇到编程语言——数组的相关文章

SDUT 3347 数据结构实验之数组三:快速转置

数据结构实验之数组三:快速转置 Time Limit: 1000MS Memory Limit: 65536KB Submit Statistic Problem Description 转置运算是一种最简单的矩阵运算,对于一个m*n的矩阵M( 1 = < m < = 10000,1 = < n < = 10000 ),它的转置矩阵T是一个n*m的矩阵,且T( i , j )=M( j , i ).显然,一个稀疏矩阵的转置仍然是稀疏矩阵.你的任务是对给定一个m*n的稀疏矩阵( m

(2)redis的基本数据结构是动态数组

redis的基本数据结构是动态数组 一.c语言动态数组 先看下一般的动态数组结构 struct MyData { int nLen; char data[0]; }; 这是个广泛使用的常见技巧,常用来构成缓冲区.比起指针,用空数组有这样的优势: 1.不需要初始化,数组名直接就是所在的偏移   2.不占任何空间,指针需要占用int长度空间,空数组不占任何空间.  这个数组不占用任何内存,意味着这样的结构节省空间: 该数组的内存地址就和他后面的元素的地址相同,意味着无需初始化,数组名就是后面元素的地

【算法与数据结构】图 -- 数组表示法

图的数组表示法 借助一个二维数组表示图,该二维数组的第i行,第j列的值表示从Node[i]到Node[j]: 无向图(网):是否有边 / 权值,arr[i][j] == arr[j][i],无向图(网)的特性,矩阵关于对角线对称. 有向图(网):是否有弧 / 权值. //图的数组表示法 //最大顶点个数 const int MAX_VERTEX = 100; //最大值 const int MAX_VALUE = (1 << 31) - 1; typedef struct _tagArcCel

数据结构——树状数组

我们今天来讲一个应用比较广泛的数据结构——树状数组 它可以在O(nlogn)的复杂度下进行单点修改区间查询,下面我会分成三个模块对树状数组进行详细的解说,分别是树状数组基本操作.树状数组区间修改单点查询的实现.树状数组查询最值的实现 一. 树状数组一般分为三种操作,初始化.修改.查询 在讲基本操作之前,我们先来看一张图 这张图就是树状数组的存储方式,对于没有接触过树状数组的人来说看懂上面这张图可能有些困难,上图的A数组就是我们的原数组,C数组则是我们需要维护的数组,这样存储能干什么呢,比如我们在

从零开始实现数据结构(一) 动态数组

从零开始实现数据结构(一) 动态数组 动态数组是所有数据结构中最简单的一种,甚至在很多的语言中,数组本身就是可以不定长的.因为在学习c++的时候,使用动态数组的各种操作都不是很方便(数据结构的学习最好还是c或c++,基础打好了其他的语言数据结构就很简单).所以开始学习如何去实现一个像STL中的vector一样的动态数组. 创建数组基类CArray 因为后面还准备写一个有序数组,所以这里使用一个CArray类,把数组的各种基本特性先创建好.后面需要写什么数组,就可以写它下面的子类,来完成特殊的功能

数据结构(一)_数组

数组基本知识 数组对于每一门编程语言来说都是重要的数据结构之一,当然不同语言对数组的实现及处理也不尽相同. Java语言中提供的数组是用来存储固定大小的同类型元素. public class Demo1 { public static void main(String[] args) { // 定义一个数组,保存五名学生的成绩 int[] scores = { 78, 93, 97, 84, 63 }; // 输出数组中的第二个成绩 System.out.println("数组中的第2个成绩为:

数据结构实践项目——数组和广义表

本文针对 [数据结构基础系列网络课程(5):数组和广义表] 1. 数组的基本概念与存储结构 2. 特殊矩阵的压缩存储 3. 稀疏矩阵的三元组表示 4. 稀疏矩阵的十字链表表示 5. 广义表 6. 广义表的存储结构及基本运算的实现 [项目1 - 猴子选大王(数组版)] 一群猴子,编号是1,2,3 -m,这群猴子(m个)按照1-m的顺序围坐一圈.从第1只开始数,每数到第n个,该猴子就要离开此圈,这样依次下来,最后一只出圈的猴子为大王.输入m和n,输出猴子离开圈子的顺序,从中也可以看出最后为大王是几号

数据结构实践——队列数组

本文是针对数据结构基础系列网络课程(3):栈和队列的实践项目. [项目 - 队列数组] 创建10个队列,分别编号为0-9(处理为队列数组,编号即下标).输入若干个正整数,以数字0作为结束.设输入的值为x,其个位数字的大小为i,则将x插入到编号为i的队列中.最后输出所有的非空队列. 要求将队列处理成链式队列,使用链式队列算法库中定义的数据类型及算法,程序中只包括一个函数(main函数),入队和出队等操作直接在main函数中调用即可. 设程序运行时输入:70 59 90 72 67 88 80 64

数据结构复习笔记--数组

最后还是决定在未来的道路上走向软件开发者这条路,从现在重新复习数据结构和算法. 关于数组有几个比较有意思的特点. 1.对于数组 int List[3],编译器将List[i]解释为指向一个地址为List + i*sizeof(int)的整数的指针. 对于int * List, int *List2[5],两个都是指向int 类型的变量,但是编译器会为后者分配五个整数存储空间. List2实际是上指向List2[0],List2 + i 实际上是&List2[i].在C语言中是不需要加上偏移量的.