王道数据结构精简笔记——顺序表(附完整工程)

一、顺序表的定义

顺序表——用顺序存储的方式实现线性表。(逻辑相邻——>物理相邻)

1. 顺序表的实现——静态分配

#define MaxSize 10				//定义最大长度
typedef struct{
    ElemType data[MaxSize];		// 用静态的“数组”存放数据元素
    int length;					// 顺序表的当前长度
}SqList;						// 顺序表的类型定义(静态分配方式)

完整例子:

#include <stdio.h>
#define MaxSize 10				// 定义最大长度
typdef 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. 顺序表的实现——动态分配

#define InitSize 10				// 顺序表的初始长度
typedef struct{
    ElemType *data;				// 指示动态分配数组的指针
    int MaxSize;				// 顺序表的最大容量
    int length;					// 顺序表的当前长度
}SeqList;						// 顺序表的类型定义(动态分配方式)

完整例子:

#include <stdio.h>
#include <stdlib.h>
#define InitSize 10				// 顺序表的初始长度
typedef struct{
    ElemType *data;				// 指示动态分配数组的指针
    int MaxSize;				// 顺序表的最大容量
    int length;					// 顺序表的当前长度
}SeqList;						// 顺序表的类型定义(动态分配方式)

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

/* 增加动态数组的长度 */
void IncreaseSize(SeqList &L, int len){
    // 指针p指向原本的L表
    int *p = L.data;			
    // L表重新申请了增加长度后的相应大小内存空间
    L.data = (int *)malloc((L.MaxSize + len) * sizeof(int));
    // 此时p指向旧内存空间,L指向新内存空间,数据仍在旧内存空间中
    for(int i = 0; i < L.length; i++){							
        L.data[i] = p[i];			// 将旧内存空间中的数据复制到新空间中
    }
    L.MaxSize = L.MaxSize + len;	// 更新顺序表的最大容量
    free(p);						// 释放旧的内存空间
}

int main(){
    SeqList L;
    InitList(L);
    
    /* ...... */
    
    IncreaseSize(L, 5);
    return 0;
}

顺序表特点:

  1. 随机访问
  2. 存储密度高
  3. 拓展容量不方便
  4. 插入、删除操作不方便

请添加图片描述

二、顺序表的插入删除(静态分配为例)

请添加图片描述

1. ListInsert(&L, i, e)

插入操作,在表L中的第i个位置上插入制定元素e。

#include <stdio.h>
#define MaxSize 10				// 定义最大长度
typdef 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
}

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;						// 在i位置放入e
    L.length ++;							// 长度+1
}

int main(){
    SqList L;					// 声明一个顺序表
    InitList(L);				// 初始化顺序表
    
    /* 后续操作 */
    
    return 0;
}

算法强壮性:

  1. 插入位序i应该在1length+1之间
  2. 当前长度是否会超过最大长度

bool函数实现(bool的返回值要么是true要么是false)

bool ListInsert(SqList &L, int i, int e){
    if (i < 1 || i > L.length + 1)		// 判断i的范围是否有效
        return false;
    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;					// 在位置i处放入e
    L.length++;							// 长度+1
    return true;
}

时间复杂度分析:

  1. 最好情况:新元素插入到表尾,i=n+1,循环0次;最好时间复杂度=O(1)
  2. 最坏情况:新元素插入到表头,i=1,循环n次;最坏时间复杂度=O(n)
  3. 平均情况:假设新元素插入到任何一个位置的概率相同,则平均循环次数=

n p + ( n − 1 ) p + ( n − 2 ) p + . . . . . . + 1 ⋅ p = [ n ( n + 1 ) / 2 ] ⋅ [ 1 / n + 1 ] = n / 2 np+(n-1)p+(n-2)p+......+1·p=[n(n+1)/2]·[1/n+1]=n/2 np+(n1)p+(n2)p+......+1p=[n(n+1)/2][1/n+1]=n/2

平均时间复杂度=O(n/2)=O(n)

2. ListDelete(&L, i, &e)

删除操作,删除表L中的第i个位置的元素,并用e返回删除元素的值。

代码实现:

bool ListDelete(SqList &L, int i, int &e){
    if(i < 1 || i > L.length)				// 判断i的范围是否有效
        return false;
    e = L.data[i - 1];						// 将被删除的元素复制给e
    for(int j = i; j < L.length; j++)		// 将第i个位置后的元素前移
        L.data[j - 1] = L.data[j];
    L.length--;								// 线性表长度-1
    return true;
}

时间复杂度分析:

  1. 最好情况:删除表位元素,i=n,循环0次;最好时间复杂度=O(1)
  2. 最坏情况:删除表头元素,i=1,循环n-1次;最坏时间复杂度=O(n)
  3. 平均情况:假设删除任何一个元素的概率相同,平均循环次数为(n-1)/2,平均时间复杂度=O(n)

请添加图片描述

三、顺序表查找

请添加图片描述

1. GetElem(L, i)

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

ElemType GetElem(SqList L, int i){
    return L.data[i - 1];
}

时间复杂度:O(1)

2. LocateElem(L, e)

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

int LocateElem(SeqList L, ElemType e){
    for(int i = 0; i < L.length; i++)
        if(L.data[i] == e)
            return i + 1;
    return 0;
}

时间复杂度:

  1. 最好情况:目标元素在表头,循环1次;最好时间复杂度=O(1)
  2. 最坏情况:目标元素在表尾,循环n次;最坏时间复杂度=O(n)
  3. 平均情况:假设目标元素出现在任何一个位置的概率都相同,平均循环次数为(n+1)/2;平均时间复杂度=O(n)

请添加图片描述

整合代码示例

#include <stdio.h>
#include <stdlib.h>
#define MaxSize 10                                          // 定义表最大长度
#define InitSize 10                                         // 定义表初始长度

/* 静态分配方式定义 */
typedef struct{
    int data[MaxSize];                                      // 存放数据元素
    int length;                                             // 当前表长
}SqList;

/* 动态分配方式定义 */
typedef struct{
    int *data;                                              // 指针指向动态分配数组
    int DMaxSize;                                           // 表的最大容量
    int length;                                             // 当前表长
}SeqList;

/* 初始化表——静态 */
void InitJList(SqList &L)
{
    for(int i = 0; i < MaxSize; i++)
        L.data[i] = 0;                                      // 表中所有元素默认为0
    L.length = 0;                                           // 表长为0
}

/* 初始化表——动态 */
void InitDList(SeqList &L)
{
    L.data = (int *)malloc(InitSize * sizeof(int));		// 用malloc函数申请一片连续的存储空间
    L.length = 0;
    L.DMaxSize = InitSize;
}

/* L1顺序表插入 */
bool SListInsert(SqList &L, int i, int e)
{
    if (i < 1 || i > L.length + 1)		// 判断i的范围是否有效
        return false;
    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;					// 在位置i处放入e
    L.length++;							// 长度+1
    return true;
}

/* L1插入实现 */
void SteListInsert(SqList &L)
{
    int i, e;
    printf("在第几个位置插入几?\n");
    scanf("%d %d",&i, &e);
    if(SListInsert(L, i, e))
    {
        printf("插入成功\n");
        printf("L1表的第%d个位置的值为%d\n", i, L.data[i-1]);
    }
    else
        printf("插入错误\n");
    printf("\n");
}

/* L2顺序表插入 */
bool LListInsert(SeqList &L, int i, int e)
{
    if (i < 1 || i > L.length + 1)		// 判断i的范围是否有效
        return false;
    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;					// 在位置i处放入e
    L.length++;							// 长度+1
    return true;
}

/* L2插入实现 */
void LivListInsert(SeqList &L)
{
    int i, e;
    printf("在第几个位置插入几?\n");
    scanf("%d %d",&i, &e);
    if(LListInsert(L, i, e))
    {
        printf("插入成功\n");
        printf("L2表的第%d个位置的值为%d\n", i, L.data[i-1]);
    }
    else
        printf("插入错误\n");
    printf("\n");
}

/* L1顺序表删除 */
bool SListDelete(SqList &L, int i, int &e)
{
    if(i < 1 || i > L.length)				// 判断i的范围是否有效
        return false;
    e = L.data[i - 1];						// 将被删除的元素复制给e
    for(int j = i; j < L.length; j++)		// 将第i个位置后的元素前移
        L.data[j - 1] = L.data[j];
    L.length--;								// 线性表长度-1
    return true;
}

/* L1删除实现 */
void SteListDelete(SqList &L)
{
    int i, e;
    printf("要删除第几个元素?\n");
    scanf("%d", &i);
    if(SListDelete(L, i, e))
    {
        printf("删除成功!\n");
        printf("删除的元素为%d\n", e);
    }
    else
        printf("删除失败\n");
    printf("\n");
}

/* L2顺序表删除 */
bool LListDelete(SeqList &L, int i, int &e)
{
    if(i < 1 || i > L.length)				// 判断i的范围是否有效
        return false;
    e = L.data[i - 1];						// 将被删除的元素复制给e
    for(int j = i; j < L.length; j++)		// 将第i个位置后的元素前移
        L.data[j - 1] = L.data[j];
    L.length--;								// 线性表长度-1
    return true;
}

/* L2删除实现 */
void LivListDelete(SeqList &L)
{
    int i, e;
    printf("要删除第几个元素?\n");
    scanf("%d", &i);
    if(LListDelete(L, i, e))
    {
        printf("删除成功!\n");
        printf("删除的元素为%d\n", e);
    }
    else
        printf("删除失败\n");
    printf("\n");
}

/* L1按位查找 */
int SGetElem(SqList L, int i)
{
    if(i < 1 || i > L.length)
        return 0;
    else
        return L.data[i - 1];
}

/* L1按位查找实现 */
void SteGetElem(SqList L)
{
    int i;
    printf("要查找第几个元素?\n");
    scanf("%d", &i);
    if(SGetElem(L, i) != 0)
        printf("第%d个元素为%d\n", i, SGetElem(L, i));
    else
        printf("超出查询范围\n");
    printf("\n");
}

/* L2按位查找 */
int LGetElem(SeqList L, int i)
{
    if(i < 1 || i > L.length)
        return 0;
    else
        return L.data[i - 1];
}

/* L2按位查找实现 */
void LivGetElem(SeqList L)
{
    int i;
    printf("要查找第几个元素?\n");
    scanf("%d", &i);
    if(LGetElem(L, i) != 0)
        printf("第%d个元素为%d\n", i, LGetElem(L, i));
    else
        printf("超出查询范围\n");
    printf("\n");
}

/* L1按值查找 */
int SLocateElem(SqList L, int e)
{
    for(int i = 0; i < L.length; i++)
        if(L.data[i] == e)
            return i + 1;
    return 0;
}

/* L1按值查找实现 */
void SteLocateElem(SqList L)
{
    int e;
    printf("请输入需要查找的数值\n");
    scanf("%d", &e);
    if(SLocateElem(L, e) == 0)
        printf("未查询到此值\n");
    else
        printf("此值在第%d个位置\n",SLocateElem(L, e));
    printf("\n");
}

/* L2按值查找 */
int LLocateElem(SeqList L, int e)
{
    for(int i = 0; i < L.length; i++)
        if(L.data[i] == e)
            return i + 1;
    return 0;
}

/* L2按值查找实现 */
void LivLocateElem(SeqList L)
{
    int e;
    printf("请输入需要查找的数值\n");
    scanf("%d", &e);
    if(LLocateElem(L, e) == 0)
        printf("未查询到此值\n");
    else
        printf("此值在第%d个位置\n",LLocateElem(L, e));
    printf("\n");
}

/* L1打印整表 */
void PrintSListElem(SqList L)
{
    if(L.length == 0)
        printf("此表为空,请先插入数值\n");
    else
        for(int i = 0; i < L.length; i++)
            printf("第%d个值:%d\n", i+1, L.data[i]);
    printf("\n");
}

/* L2打印整表 */
void PrintLListElem(SeqList L)
{
    if(L.length == 0)
        printf("此表为空,请先插入数值\n");
    else
        for(int i = 0; i < L.length; i++)
            printf("第%d个值:%d\n", i+1, L.data[i]);
    printf("\n");
}

int main()
{
    int i;
    SqList L1;                                              // 声明顺序表(静态分配)
    SeqList L2;                                             // 声明顺序表(动态分配)
    InitJList(L1);                                          // 初始化静态分配顺序表
    InitDList(L2);                                          // 初始化动态分配顺序表

    while(1)
    {
        printf("请输入操作:\n");
        printf("1.L1表插入数值;\n");
        printf("2.L2表插入数值;\n");
        printf("3.L1表删除数值;\n");
        printf("4.L2表删除数值;\n");
        printf("5.L1表按位查找;\n");
        printf("6.L2表按位查找;\n");
        printf("7.L1表按值查找;\n");
        printf("8.L2表按值查找;\n");
        printf("9.打印L1表;\n");
        printf("10.打印L2表;\n");
        printf("11.退出;\n");
        scanf("%d", &i);
        switch(i)
        {
            case 1: SteListInsert(L1);      break;
            case 2: LivListInsert(L2);      break;
            case 3: SteListDelete(L1);      break;
            case 4: LivListDelete(L2);      break;
            case 5: SteGetElem(L1);         break;
            case 6: LivGetElem(L2);         break;
            case 7: SteLocateElem(L1);      break;
            case 8: LivLocateElem(L2);      break;
            case 9: PrintSListElem(L1);     break;
            case 10: PrintLListElem(L2);    break;
        }
        if(i == 11)
            break;
    }

    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值