算法与数据结构系列之[线性表的顺序存储结构]

在这里插入图片描述
说到线性表的顺序存储结构,我们平时最常用的数组就是顺序存储结构,即用一段地址连续的存储单元依次存储线性表的数据元素。说的通俗一点,就是需要为数组在内存中开辟连续的存储空间。这样连续的存储结构也是优缺点非常明显的,因为数组元素的存储地址是连续的,所以查询起来就很方便,通过数组元素的下标就可以查询到任意的数组元素,且查询的时间复杂度为O(1),对于大数据量的查询性能优势很明显,这也是随机存取的好处。但是数组元素的插入和删除操作的缺点也就很突出了,每插入和删除一个元素,就需要将从该位置起所有的元素向后或向前移动。在最好的情况下,如果元素要插入到最后一个位置,或者删除最后一个元素,此时的时间复杂度为O(1)。最坏的情况是,如果元素要插入到第一个位置或是删除第一个元素,此时的时间复杂度就是O(n)了,插入到第i个位置的平均时间复杂度也是O(n),可以得出数组的插入和删除操作的时间复杂度就是O(n),所以对于大数据量的数组频繁的插入和删除操作,这样的性能消耗也是很大的,此时使用链表就比使用数组更合适。

C语言代码 (IDE使用的是CLion,至于IDE的配置,大家可以网上找找,不懂的地方可以关注我的微信公众号:源码复兴号,加我微信联系我):
1、SqList.c

#define INITSIZE 100  //线性表存储空间的初始分配量
#define OK 1
#define ERROR 0
#define LISTINCREMENT 10 //线性表存储空间的分配增量
#define TRUE 1
#define FALSE 0

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

typedef int ElementType;
typedef int Status;

def struct {
    ElementType *data;  //声明了一个名为data的长度不确定的数组,也叫“动态数组”
    int length; //记录当前顺序表的长度
    int size; //记录顺序表分配的存储容量
}SqList;
/**
* 初始化顺序表
* @param L
* @return
*/
Status  InitList(SqList *L){
    L->data = (ElementType *)malloc(INITSIZE* sizeof(ElementType));  //分配存储空间为100
    if(!L->data) exit(0); //存储分配失败
    L->length = 0; //初始线性表长度为0
    L->size = INITSIZE; //初始存储容量
    return OK;
}

/**
* 查询第i个位置的元素值,并用e返回
* @param L
* @param i
* @param e
* @return
*/
Status GetElem(SqList L,int i,ElementType *e){
    if(L.length==0 || i<1 || i>L.length)
        return ERROR;
    *e=L.data[i-1];
    return OK;
}

/**
* 在第I的位置插入元素
* @param L
* @param i
* @param e
* @return
*/
Status ListInsert(SqList *L,int i,ElementType e){
    int k;
    if(i<1 || i>L->length+1) //当i不在范围内
        return ERROR;
    if(L->length >= L->size){    //当前的存储空间已满时,增加内存分配
        L->data =(ElementType *)realloc(L->data,(L->size+LISTINCREMENT)* sizeof(ElementType));
        if(!L->data)  //存储分配失败
            exit(0);
        L->size += LISTINCREMENT; //增加存储容量
    }
    if(i<=L->length){
        for (int k = L->length-1; k >=i-1 ; k--) {
            L->data[k+1]=L->data[k];
        }
    }
    L->data[i-1]=e;
    L->length++;
    return OK;
}

/**
* 删除线性表中第i个位置的元素
* @param L
* @param i
* @param e
* @return
*/
Status ListDelete(SqList *L,int i,ElementType *e){
    int k;
    if(L->length == 0)
        return ERROR;
    if(i<1 || i>L->length)  //i的值不合法
        return ERROR;
    *e=L->data[i-1];
    if(i<L->length){
        for (int k = i; k < L->length; k++) {
            L->data[k-1] = L->data[k];
        }
    }
    L->length--;
    return OK;
}

/**
* 判断线性表是否为空
* @param list
* @return
*/
Status ListEmpty(SqList list){
    if(list.length == 0)
        return TRUE;
    return FALSE;
}

/**
* 清空线性表,将线性表L置为一个空表
* @param L
* @return
*/
Status ClearList(SqList *L){
    L->length = 0;
    return OK;
}

/**
* 销毁线性表,释放内存
* @param L
* @return
*/
Status DestroyList(SqList *L){
    if(L->data){
        free(L->data);
        L->data = NULL;
        L->size =0;
        return TRUE;
    }
    return FALSE;
}

/**
* 返回线性表中元素个数
* @param L
* @return
*/
int ListLength(SqList L){
    return L.length;
}

/**
* 返回线性表的内存容量
* @param L
* @return
*/
int ListSize(SqList L){
    return L.size;
}

/**
* 遍历打印线性表元素
* @param L
*/
void DisplayList(SqList L){
    for (int i = 0; i < L.length; i++) {
        printf("%d ",L.data[i]);
    }
}

2、SqList.h

#ifndef TEST_SQLIST_H
#define TEST_SQLIST_H
typedef int ElementType;
typedef int Status;
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

typedef struct {
    ElementType *data;  //声明了一个名为data的长度不确定的数组,也叫“动态数组”
    int length; //记录当前顺序表的长度
    int size; //记录顺序表分配的存储容量
}SqList;

//初始化线性表
Status  InitList(SqList *L);

//查询第i个位置的元素
Status GetElem(SqList L,int i,ElementType *e);

//添加元素
Status ListInsert(SqList *L,int i,ElementType e);

//删除元素
Status ListDelete(SqList *L,int i,ElementType *e);

//判断线性表是否为空
Status ListEmpty(SqList list);

//清空线性表,将线性表L置为一个空表
Status ClearList(SqList *L);

//销毁线性表,释放内存
Status DestroyList(SqList *L);

//返回线性表中元素个数
int ListLength(SqList L);

//返回线性表的内存容量
int ListSize(SqList L);

//遍历打印线性表元素
void DisplayList(SqList L);
#endif //TEST_SQLIST_H

3、main.c

#include <stdio.h>
#include "src/hello.h"
#include "src/data/SqList.h"
int main() {
    //初始化一个具有20个元素的线性表
    SqList list;
    InitList(&list);
    for (int i = 1; i <=20 ; i++) {
        list.data[i-1]=i;
        list.length++;
    }

    //遍历线性表
    DisplayList(list);
    printf("\n");

    //输出线性表的长度,即线性表元素个数
    printf("%d",ListLength(list));
    printf("\n");

    //线性表是否为空
    printf("%d",ListEmpty(list));
    printf("\n");

    //打印线性表中第三个位置的元素
    int num ;
    int *n =&num;
    GetElem(list,3,n);
    printf("%d",*n);
    printf("\n");

    //给线性表添加一个元素,并重新遍历
    ListInsert(&list,5,30);
    DisplayList(list);
    printf("\n");

    //删除线性表指定位置的元素,并重新遍历,并打印出将要删除的元素
    int delete;
    int *d = &delete;
    ListDelete(&list,10,d);
    printf("%d",*d);
    printf("\n");
    DisplayList(list);
    printf("\n");

    //清空线性表
    ClearList(&list);
    DisplayList(list);  //此次遍历线性表中已经没有元素
    printf("\n");
    printf("%d",ListLength(list));  //元素个数为0
    printf("\n");
    printf("%d",ListSize(list));  //此时给线性表分配的内存容量还为100
    printf("\n");

    //销毁线性表,并释放内存
    int result = DestroyList(&list);
    DisplayList(list);  //此次遍历线性表中已经没有元素
    printf("\n");
    printf("%d",ListLength(list));  //元素个数为0
    printf("\n");
    printf("%d",ListSize(list));  //此时给线性表分配的内存容量0
    printf("\n");
    return 0;
}

4、运行结果

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
20
0
3
1 2 3 4 30 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
9
1 2 3 4 30 5 6 7 8 10 11 12 13 14 15 16 17 18 19 20

0
100

0
0

java代码:

public class Array<E>{
    private E[] data;
    private int size;

    /**
     * 构造函数,传入数组容量capacity构造array
     * @param capacity
     */
    public Array(int capacity){
        data = (E[]) new Object[capacity];
        size = 0;
    }

    /**
     * 无参构造,数组的容量默认为100
     */
    public Array(){
        this(10);
    }

    public Array(E[] arr){
        data = (E[]) new Object[arr.length];
        for (int i = 0; i < arr.length; i++) {
            data[i] = arr[i];
        }
    }
    /**
     * 获取数组的元素个数
     * @return
     */
    public int getSize(){
        return size;
    }

    /**
     * 获取数组容量
     * @return
     */
    public int getCapacity(){
        return data.length;
    }

    /**
     * 判断数组是否为空
     * @return
     */
    public boolean isEmpty(){
        return size == 0;
    }

    /**
     * 向数组指定位置插入元素
     * @param index
     * @param e
     */
    public void add(int index,E e){
        if(index<0 || index>size){
            throw  new IllegalArgumentException("下标越界");
        }
        if(size == data.length){
            resize(2*data.length);
        }
        for(int i=size-1;i>=index;i--){
            data[i+1] = data[i];
        }
        data[index] = e;
        size++;
    }

    /**
     * 向数组的第一个位置添加元素
     * @param e
     */
    public void addFirst(E e){
        add(0,e);
    }

    /**
     * 向数组的最后一个位置添加元素
     * @param e
     */
    public void addLast(E e){
        add(size,e);
    }

    /**
     * 当数组容量已满时自动扩容2倍
     * @param newCapacity
     */
    private void resize(int newCapacity) {
        E[] newData = (E[]) new Object[newCapacity];
        for (int i = 0; i <size ; i++) {
            newData[i] = data[i];
        }
        data = newData;
    }

    /**
     * 向数组中插入元素
     * @param e
     */
    public void add(E e){
        add(size,e);
    }

    @Override
    public String toString() {
        StringBuilder res = new StringBuilder();
        res.append(String.format("Array: size = %d , capacity = %d\n",size,data.length));
        res.append("[");
        for (int i = 0; i <size ; i++) {
            res.append(data[i]);
            if(i != size-1){
                res.append(",");
            }
        }
        res.append("]");
        return res.toString();
    }

    /**
     * 查询指定位置的数组元素
     * @param index
     * @return
     */
    public E get(int index){
        if(index < 0 || index > size){
            throw new IllegalArgumentException("传入的数组索引值不合法");
        }
        return data[index];
    }

    /**
     * 查询数组的第一个元素
     * @return
     */
    public E getFirst(){
        return get(0);
    }

    /**
     * 查询数组的最后一个元素
     * @return
     */
    public E getLast(){
        return get(size-1);
    }

    /**
     * 修改数组指定位置的元素
     * @param index
     * @param e
     */
    public void set(int index,E e){
        if(index < 0 || index > size){
            throw new IllegalArgumentException("传入的数组索引值不合法");
        }
        data[index] = e;
    }

    /**
     * 查询数组中是否包含某个元素e
     * @param e
     * @return
     */
    public boolean contains(E e){
        for (int i = 0; i <size; i++) {
            if(data[i] == e){
                return true;
            }
        }
        return false;
    }

    /**
     * 查询并返回某个元素e的下标
     * @param e
     * @return
     */
    public int find(E e){
        for (int i = 0; i < size; i++) {
            if(data[i] == e){
                return i;
            }
        }
        return -1;
    }

    /**
     * 删除指定索引值的元素,并返回该元素
     * @param index
     * @return
     */
    public E remove(int index){
        if(index<0 || index>size){
            throw  new IllegalArgumentException("所传入的数组索引值不合法");
        }
        E ret = data[index];
        for (int i = index + 1; i <size ; i++) {
            data[i-1] = data[i];
        }
        data[--size] = null;
        if(size == data.length/4 && data.length/2 !=0){
            resize(data.length/2);
        }
        return ret;
    }

    /**
     * 删除数组的第一个元素
     * @return
     */
    public E removeFirst(){
        return remove(0);
    }

    /**
     * 删除数组的最后一个元素
     * @return
     */
    public E removeLast(){
        return remove(size-1);
    }

    /**
     * 从数组中删除元素e
     * @param e
     */
    public boolean removeElement(E e){
        int index = find(e);
        if(index != -1){
            remove(index);
            return true;
        }
        return false;
    }

    /**
     * 数组元素交换
     * @param i
     * @param j
     */
    public void swap(int i,int j){
        if(i < 0 || i >= size || j < 0 || j >= size)
            throw new IllegalArgumentException("非法索引");
        E temp = data[i];
        data[i] = data[j];
        data[j] = temp;

    }
}

微信公众号:
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值