-->

数据结构中的顺序表


顺序表

数据结构中的物理结构(存储结构)分为顺序结构和链式结构。

  • 顺序结构:是在内存中申请一块连续的空间来存储数据(可以理解为数组),一般情况下都是在堆内存申请空间。

下面是如何创建顺序表:

  1. 一般情况下,需要有几个变量记录顺序表的数据(如顺序表的长度、顺序表存储的元素个数,顺序表的首地址),这些数据使用一个结构体来存储即可。

image

//顺序表存放的数据类型,使用这个类型可以在这修改顺序表中存储的数据类型
typedef int DataType_t;

//1.需要建立顺序表的管理结构体
typedef struct seqlist
{
    DataType_t * Addr;      //顺序表的首地址
    unsigned int Size;      //顺序表的容量
    int          Last;      //顺序表的存储个数
}Seqlist_t;
  1. 第二步就是创建顺序表
/****************************************************
*       函数名称:   SeqList_Create
*       函数功能:   新建顺序表
*       函数参数:   
*                   @size:创建顺序表的大小
*       返回结果:   返回顺序表管理者的地址
*       注意事项:   None
*       函数作者:
*       创建日期:   2024/04/19
*       修改历史:
*       函数版本:   V1.0
***************************************************/
Seqlist_t * SeqList_Create(unsigned int size)
{
    //1.首先需要一个管理者
    Seqlist_t * Manager = (Seqlist_t *)calloc(1,sizeof(Seqlist_t));
    if(NULL == Manager){
        perror("calloc for Manager is failed!!!");
        exit(-1);
    }
    //2.建立顺序表的堆空间,堆空间的首地址由管理者的addr成员管理
    Manager->Addr = (DataType_t*) calloc(size,sizeof(DataType_t));
    if(NULL == Manager->Addr){
        perror("calloc for Manager is failed!!!");
        free(Manager);
        Manager = NULL;
        exit(-1);
    }

    //3.顺序表创建完成需要初始化
    Manager->Size = size;
    //元素的下标从-1开始表示没有元素
    Manager->Last = -1;

    return Manager;
}
  • 有了顺序表接下来就是对顺序表进行增删改查

顺序表元素的插入

为顺序表添加元素,添加元素有三种情况,在尾部添加,中间添加,头部添加。时间复杂度依次增加,因为需要遍历的元素增加。

  • 首先在尾部添加,这是最简单的情况,一共两个函数,第一个是判断顺序表是否已满,第二个是在尾部添加元素。

image

/****************************************************
*       函数名称:   SeqList_IsFull
*       函数功能:   判断顺序表是否已满
*       函数参数:   
*                   @Manager:顺序表管理者的地址
*       返回结果:   true:已满。false:未满。
*       注意事项:   None
*       函数作者:
*       创建日期:   2024/04/19
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool SeqList_IsFull(Seqlist_t * Manager)
{
    return (Manager->Last+1 == Manager->Size) ? true : false ;
}

/****************************************************
*       函数名称:   SeqList_TailAddEle
*       函数功能:   给顺序表尾部添加新的元素
*       函数参数:   
*                   @Manager:顺序表管理者的地址
*                   @data   :添加的数据
*       返回结果:   true:添加成功。false:添加失败。
*       注意事项:   None
*       函数作者:
*       创建日期:   2024/04/19
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool SeqList_TailAddEle(Seqlist_t * Manager,DataType_t data)
{
    //1.首先判断顺序表是否已满
    if( SeqList_IsFull(Manager) ){
        printf("sequence list is full!\n");
        return false;
    }

    //2.未满可以插入,在尾部插入,插入完成之后也需要个数需要加一
    Manager->Addr[++Manager->Last] = data;//给最后一个元素赋值后加一

    return true;
}
  • 第二是在中间添加,把需要插入的地方的元素,以及后面的元素向后移动一位即可。

image

/****************************************************
*       函数名称:   SeqList_MediumAddEle
*       函数功能:   给顺序表中间添加新的元素
*       函数参数:   
*                   @Manager		:顺序表管理者的地址
*                   @data   		:添加的数据
*                   @dest_data    	:需要在第几个数据后面添加
*       返回结果:   true:添加成功。false:添加失败。
*       注意事项:   在中间插入后其余元素会滞后。
*       函数作者:
*       创建日期:   2024/04/19
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool SeqList_MediumAddEle(Seqlist_t * Manager,DataType_t dest_data,DataType_t data)
{
    //1.首先判断顺序表是否已满
    if( SeqList_IsFull(Manager) ){
        printf("sequence list is full!\n");
        return false;
    }

	int num = 0;
	//2.先寻找到这个数据所在的位置,需要记住元素所在的位置
	for(num = 0;(dest_data != Manager->Addr[num]) && (num < Manager->Last);num++);

	//判断是否有这个数据
	if((num == Manager->Last) && (dest_data != Manager->Addr[num])){
		printf("dest_data(%d) is exist!!!\n",dest_data);
		return false;
	}

	//判断是否为顺序表最后一个,最后一个不需要移动直接添加
	if(num == (Manager->Last)){
		Manager->Addr[num+1] = data;
		Manager->Last++;
		
		return true;
	}
	
	//3.将指定的位置以及后面都向后移动
	for(int j = Manager->Last;j > num;j--){
		Manager->Addr[j+1] = Manager->Addr[j];
	}
	
    //4.将元素赋值给这个下标的位置,并且元素个数加一
    Manager->Addr[num+1] = data;
    Manager->Last++;

    return true;
}

  • 最后是在头部插入,需要把所有的元素向后偏移

image

/****************************************************
*       函数名称:   SeqList_HeadAddEle
*       函数功能:   给顺序表头部添加新的元素
*       函数参数:   
*                   @Manager:顺序表管理者的地址
*                   @data   :添加的数据
*       返回结果:   true:添加成功。false:添加失败。
*       注意事项:   None
*       函数作者:
*       创建日期:   2024/04/19
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool SeqList_HeadAddEle(Seqlist_t * Manager,DataType_t data)
{
    //1.首先判断顺序表是否已满
    if( SeqList_IsFull(Manager) ){
        printf("sequence list is full!\n");
        return false;
    }

    //2.没有满需要把前面的元素往后挪
    for(int i = Manager->Last;i >= 0;i--){
        Manager->Addr[i+1] = Manager->Addr[i];
    }
    //3.移动之后,第一个元素空闲,直接放置数据,别忘记数据加一
    Manager->Addr[0] = data;
    Manager->Last++;

    return true;
}

顺序表元素的删除

接下来是删除元素,删除元素也是分为了三种,尾部插入、中间插入、头部插入,时间复杂度也是依次增加。

  • 尾部删除,直接把有效数据的下标减一即可。每一次删除元素都需要判断顺序表是否有元素

image

/****************************************************
*       函数名称:   SeqList_IsEmpty
*       函数功能:   判断顺序表是否为空
*       函数参数:   
*                   @Manager:顺序表管理者的地址
*       返回结果:   true:为空。false:不为空。
*       注意事项:   None
*       函数作者:
*       创建日期:   2024/04/19
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool SeqList_IsEmpty(Seqlist_t * Manager)
{
    return (Manager->Last == -1) ? true : false ;
}


/****************************************************
*       函数名称:   SeqList_TailDelEle
*       函数功能:   在顺序表的尾部删除元素
*       函数参数:   
*                   @Manager:顺序表管理者的地址
*       返回结果:   true:删除成功。false:删除失败。
*       注意事项:   None
*       函数作者:
*       创建日期:   2024/04/19
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool SeqList_TailDelEle(Seqlist_t * Manager)
{
    //1.首先需要顺序表是否为空
    if(SeqList_IsEmpty(Manager)){
        printf("sequence list is empty!\n");
        return false;
    }
	
    Manager->Last--;

    return true;
}
  • 中间删除元素。

image

/****************************************************
*       函数名称:   SeqList_MediumDelEle
*       函数功能:   在顺序表的中间删除元素
*       函数参数:   
*                   @Manager	:顺序表管理者的地址
*					@data		:需要删除的数据
*       返回结果:   true:删除成功。false:删除失败。
*       注意事项:   后面的数据会向前覆盖,数据的部分下标会发生变化
*       函数作者:
*       创建日期:   2024/04/19
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool SeqList_MediumDelEle(Seqlist_t * Manager,DataType_t data)
{
    //1.首先需要顺序表是否为空
    if(SeqList_IsEmpty(Manager)){
        printf("sequence list is empty!\n");
        return false;
    }
	
	//2.先寻找到数据,并且记住元素的下标
	int num = 0;
	for(num = 0;(data != Manager->Addr[num]) && (num < Manager->Last);num++);
	
	//判断是否有这个数据
	if((num == Manager->Last) && (data != Manager->Addr[num])){
		printf("data(%d) is exist!!!\n",data);
		return false;
	}

	//判断是否为最后一个元素
	if( num == Manager->Last){
		//把有效数据下标减一
		Manager->Last--;
		return true;
	}
	
    //3.把数据向前覆盖
    for(int i = num;i < Manager->Last;i++){
        Manager->Addr[i] = Manager->Addr[i+1];
    }
	
	//4.把有效数据下标减一
    Manager->Last--;

    return true;
}
  • 头部删除元素

image

/****************************************************
*       函数名称:   SeqList_HeadDelEle
*       函数功能:   在顺序表的头部删除元素
*       函数参数:   
*                   @Manager:顺序表管理者的地址
*       返回结果:   true:删除成功。false:删除失败。
*       注意事项:   后面的数据会向前覆盖,数据的下标会发生变化
*       函数作者:
*       创建日期:   2024/04/19
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool SeqList_HeadDelEle(Seqlist_t * Manager)
{
    //1.首先需要顺序表是否为空
    if(SeqList_IsEmpty(Manager)){
        printf("sequence list is empty!\n");
        return false;
    }

    //2.把数据向前覆盖
    for(int i = 0;i < Manager->Last;i++){
        Manager->Addr[i] = Manager->Addr[i+1];
    }
	//3.把有效数据下标减一
    Manager->Last--;

    return true;
}

顺序表元素的修改

接下来是修改元素,修改元素分为两个,第一个是根据数据修改(相同的数据也会被修改),第二个是下标修改

  • 数据修改
/***************************************************
*       函数名称:   SeqList_DataRecEle
*       函数功能:   按元素的数据修改元素
*       函数参数:   
*                   @Manager    :顺序表管理者的地址
*                   @scr_data   :顺序表中的数据,源数据
*                   @desk_daat  :需要修改的数据,目标数据
*       返回结果:   true:修改成功。false:修改失败。
*       注意事项:   所有相同的元素都会修改成dest_data
*       函数作者:
*       创建日期:   2024/04/20
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool SeqList_DataRecEle(Seqlist_t * Manager,DataType_t scr_data,DataType_t desk_daat)
{
    //1.首先需要顺序表是否为空
    if(SeqList_IsEmpty(Manager)){
        printf("sequence list is empty!\n");
        return false;
    }    

	int cnt = 0;//计算修改的次数
    //2.查找到顺序表中相同的元素进行修改
    for(int i = 0;i <= Manager->Last ;i++){
        if(Manager->Addr[i] == scr_data){
            Manager->Addr[i] = desk_daat;
			cnt++;
        }
    }
	//没有修改到元素,没有查找到这个数据
	if(cnt == 0){
		printf("scr_data(%d) is exist!!!\n",scr_data);
		return false;
	}

    return true;
}
  • 下标修改
/****************************************************
*       函数名称:   SeqList_SubRecEle(rectify)
*       函数功能:   按元素的下标修改元素
*       函数参数:   
*                   @Manager        :顺序表管理者的地址
*                   @num            :需要修改数据元素的下标
*                   @data     		:需要修改的数据,目标数据
*       返回结果:   true:修改成功。false:修改失败。
*       注意事项:   None
*       函数作者:
*       创建日期:   2024/04/20
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool SeqList_SubRecEle(Seqlist_t * Manager,unsigned int num,DataType_t data)
{
    //1.首先需要顺序表是否为空
    if(SeqList_IsEmpty(Manager)){
        printf("sequence list is empty!\n");
        return false;
    }
	
	//2.判断下标是否有效
	if(num > Manager->Last){
		printf("num(%d) is invalid!\n",num);
        return false;
	}

    //2.直接根据下标修改元素
    Manager->Addr[num] = data;
    return true;
}

顺序表元素的查找

顺序表元素的查找使用下标查找元素

  • 下标查找元素,返回元素的数据
/****************************************************
*       函数名称:   SeqList_SubDeteEle
*       函数功能:   按元素的下标查找元素
*       函数参数:   
*                   @Manager:顺序表管理者的地址
*                   @num    :下标
*       返回结果:   返回查找的数据,顺序表为空不返回值
*       注意事项:   None
*       函数作者:
*       创建日期:   2024/04/20
*       修改历史:
*       函数版本:   V1.0
***************************************************/
DataType_t SeqList_SubDeteEle(Seqlist_t * Manager,unsigned int num)
{
    //1.首先需要顺序表是否为空
    if(SeqList_IsEmpty(Manager)){
        printf("sequence list is empty!\n");
        return ;
    }
	
	//判断下标是否有效
	if(num > Manager->Last){
		printf("num(%d) is invalid!\n",num);
		return ;
	}

    return Manager->Addr[num];
}

顺序表的删除

完成顺序表元素的增删改查之后,别忘记顺序表是从堆区申请的内存,需要程序员手动释放

/***************************************************
*       函数名称:   SeqList_Dle
*       函数功能:   删除顺序表
*       函数参数:   
*                   @Manager    :顺序表管理者的地址
*       返回结果:   true:删除成功。false:删除失败。
*       注意事项:   None
*       函数作者:
*       创建日期:   2024/04/20
*       修改历史:
*       函数版本:   V1.0
***************************************************/
bool SeqList_Dle(Seqlist_t * Manager)
{
    //1.判断管理者是否存在
    if(NULL == Manager){
        printf("sequence list is no exist");
        return false;
    }
    //2.先把顺序表删除,在删除管理者
    free(Manager->Addr);
    Manager->Addr = NULL;
    free(Manager);
    Manager = NULL;
    return true;
}
  • 需要的头文件
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
  • 顺序表到这里就结束了,更多的功能可以自己加上去。
posted @ 2024-04-22 19:53  wuju  阅读(60)  评论(0)    收藏  举报