第二章 数据结构-顺序表


第二章 数据结构-顺序表

一、定义

1.顺序表的概念

顺序表:用顺序存储的方式实现线性表。

顺序存储:把逻辑上相邻的元素存储在物理位置上也相邻的存储单元中,元素之间的关系由存储单元的邻接关系来体现。

顺序表定义

E g . Eg. Eg. 一个Customer数据类型所占的内存大小。

typedef struct{
    int num;	//号数
    int peopele;	//人数
}Customer;

sizeof(int)=4B

sizeof(Customer)=8B

2.顺序表的实现

2.1 静态分配
#define MaxSize 10				//定义最大长度
typedef struct{					
    ElemType data[MaxSize];		
    int length;					//顺序表的当前长度
}SqLsit;						//顺序表的类型定义(静态分配方式)

E g . Eg. Eg.

#include<stdio.h>
#define MaxSize 10				//定义最大长度
typedef struct{
    int data[MaxSize];			//用静态的“数组”存放数据元素
    int length;					//顺序标的当前长度
}SqList;						//顺序表的类型定义

//基本操作-初始化一个顺序表
void InitList(SqList &L){
    for(int i=0;i<MaxSize;i++){
        L.data[i]=0;
    }
    L.length=0;					//顺序表初始长度为0
}

int main(){
    SqList L;					//声明一个顺序表
    InitList(L);				//初始化顺序表
    return 0;
}
2.2 动态分配
#define InitSize 10				//顺序表的初始长度
typedef struct{					
    ElemType *data;				//指示动态分配数组的指针
    int MaxSize;				//顺序表的最大容量
    int length;					//顺序标的当前长度
}SqLsit;						//顺序标的类型定义(动态分配方式)

C语言–mallocfree

·malloc函数返回一个指针,需要强制转型为你定义的数据元素类型指针。

L.data=(ElemType*)malloc(sizeof(ElemType)*InitSize);

E g . Eg. Eg.

#include<stdio.h>
#include<stdlib.h>
#define InitSize 10				//默认的最大长度
typedef struct{
    int *data;					//指示动态分配数组的指针
    int MaxSize;				//顺序表的最大容量
    int length;					//顺序标的当前长度
}SqList;

void InitList(SqList &L){
    //使用malloc函数申请一片连续的存储空间
    L.data=(int *)malloc(InitSize*sizeof(int));
    L.length=0;
    L.MaxSize=InitSize;
}

//增加动态数组的长度
void IncreaseSize(SqList &L,int len){
    int *p=L.data;
    L.data=(int *)malloc((L.MaxSize+len)*sizeof(int));
    for(int i=0;i<L.length;i++){
        L.data[i]=p[i];			//将数据复制到新区域
    }
    L.MaxSize=L.MaxSize+len;	//顺序表最大长度增加len
    free(p);					//释放原来的内存空间
}

int main(){
    SqList L;					//声明一个顺序表
    InitList(L);				//初始化顺序表
    //在顺序表中插入元素
    IncreaseSize(L,5);
    return 0;
}

3.顺序表的特点

(1)随机访问,即可以在 O ( 1 ) O(1) O1 时间内找到第i个元素。

(2)存储密度高,每个节点只存储数据元素。

(3)拓展容量不方便。

(4)插入、删除操作不方便,需要移动大量元素。

二、插入与删除

1.插入

#define MaxSize 10
typedef struct{
   int data[MaxSize];
   int length;
}SqList;

//...省略了初始化函数

void ListInsert(SqList &L,int i,int e){
   for(int j=L.length;j>=i;j--){   //将第i个元素及之后的元素后移
       L.data[j]=L.data[j-1];
   }
   L.data[i-1]=e;
   L.length++;
}

int main(){
   SqList L;
   InitList(L);
   ListInsert(L,3,3);
   return 0;
}

完善一下插入函数,使其更加健全,用户使用可以得到反馈。

bool ListInsert(SqList &L,int i,int e){
    if(i<1 || i>L.length+1) return false;   //i的范围无效
    if(L.length>=MaxSize)   return false;   //存储空间已满
    for(int j=L.length;j>=i;j--){   //将第i个元素及之后的元素后移
        L.data[j]=L.data[j-1];
    }
    L.data[i-1]=e;
    L.length++;
    return true;
}

时间复杂度计算:

最好情况:新元素插入到表尾,不需要移动元素

​ i=n+1,循环0次,最好时间复杂度= O ( 1 ) O(1) O(1)

最坏情况:新元素插入到表头,需要将原有n个元素全部向后移动

​ i=1,循环n次,最坏时间复杂度= O ( n ) O(n) O(n)

平均情况:假设新元素插入到任何一个位置的概率相同,即i=1,2,3…,length+1的概率都是 p = 1 n + 1 p=\frac{1}{n+1} p=n+11

​ i=1,循环n次,i=2,循环n-1次…i=n+1,循环0次

​ 平均循环次数= n 2 \frac{n}{2} 2n平均时间复杂度= O ( n ) O(n) O(n)

2.删除

bool ListDelete(SqList &L,int i,int &e){
    if(i<1 || i>L.length) return false;   //i的范围无效
    e=L.data[i-1];      //将被删除的元素赋值给e
    for(int j=i;j<L.length;j++){   //将第i个元素及之后的元素后移
        L.data[j-1]=L.data[j];
    }
    L.length--;
    return true;
}

int main(){
    SqList L;
    InitList(L);
    int e=-1;
    if(ListDelete(L,3,e)){
        printf("已删除第3个元素,删除元素的值为=%d\n",e);
    }
    else{
        printf("位序i不合法,删除失败\n");
    }
    return 0;
}

时间复杂度计算:

最好情况:删除表尾元素,不需要移动元素

​ i=n,循环0次,最好时间复杂度= O ( 1 ) O(1) O(1)

最坏情况:删除表头元素,需要将原有n-1个元素全部向前移动

​ i=1,循环n-1次,最坏时间复杂度= O ( n ) O(n) O(n)

平均情况:假设删除任何一个元素的概率相同,即i=1,2,3…,length的概率都是 p = 1 n p=\frac{1}{n} p=n1

​ i=1,循环n-1次,i=2,循环n-2次…i=n,循环0次

​ 平均循环次数= n − 1 2 \frac{n-1}{2} 2n1平均时间复杂度= O ( n ) O(n) O(n)

三、查找

1.按位查找

GetElem(L,i)按位查找操作。获取表L中第i个位置的元素的值。

1.1 静态存储
#define MaxSize 10
typedef struct{
    ElemType data[MaxSize];
    int length;
}SqList;

ElemType GetElem(SqList L,int i){
    return L.data[i-1];
}
1.2 动态存储
#define InitSize 10
typedef struct{
    ElemType *data;
    int MaxSize;
    int length;
}SqList;

ElemType GetElem(SqList L,int i){
    return L.data[i-1];
}
1.3 时间复杂度

按位查找的时间复杂度为 O ( 1 ) O(1) O(1)

2.按值查找

LocateElem(L,e)按值查找操作。在表L中查找具有给定关键字值的元素。

#define InitSize 10
typedef struct{
    ElemType *data;
    int MaxSize;
    int length;
}SqList;

//在表L中查找第一个元素值等于e的元素,并返回其位序
int LocateElem(SqList L,ElemType e){
    for(int i=0;i<L.length;i++){
        if(L.data[i]==e){	//==仅可以用于基本数据类型比较,如结构体则无法比较
            return i+1;
        }
    }
    return 0;
}

时间复杂度:

最好情况:目标元素在表头

​ 循环1次,最好时间复杂度= O ( 1 ) O(1) O(1)

最坏情况:目标元素在队尾

​ 循环n次,最坏时间复杂度= O ( n ) O(n) O(n)

平均情况:假设目标元素出现在任何一个位置的概率相同,都是 1 n \frac{1}{n} n1

​ 目标元素在第1位,循环1次,在第2为,循环2次…第n位,循环n次

​ 平均循环次数= n + 1 2 \frac{n+1}{2} 2n+1平均时间复杂度= O ( n ) O(n) O(n)

本文为个人学习笔记,若有问题可一起讨论学习
更多内容可以关注个人博客:Ackow的博客

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值