一个菜鸟的数据结构学习之路一(线性表篇,望大佬斧正!)

线性表:线性表的顺序储存结构是一种随机存取的储存结构

以下代码及注释则是其基本操作的简单实现:

  • 线性表的动态分配顺序储存结构:

储存结构中最基本的应该是存放数据元素的起始地址,然后还有相应的线性中数据个数和总的最大存放数据个数
struct list
{
ElemType *elem; //存放数据元素的基址
int length; //当前线性表的长度
int listsize; //当前分配的储存容量
}SqList;

- 相关宏定义:

为方便后面的程序修改,因此可以使用宏定义
# define LIST_INIT_ZIZE //线性表储存空间的初始值
# define LISTINCREMENT //线性表储存空间的分配增量
#define OVERFLOW 1
#define ERROR 0
#define OK 1
typedef int Status;
//Status :函数返回值(一般替换int型)

函数声明:

Status InitList(SqList &L); /*构造一个空的线性表L*/

Status ListEmpty(SqList L);  /*判断是否为空表*/

Status ListFull(SqList L);  /*判断是否为满表*/

Status ClearList(SqList &L);  /*将L重置为空表*/

Status DestroyList(SqList &L); /*销毁线性表*/

Status ListLength(SqList L); /*线性表的长度*/

Status GetElem(SqList L,int i,ElemType &e); /*查找L中第i个元素,并用e表示其值*/

Status LocateElem(SqList L,ElemType e) /*查找L中第一个与e满足关系相等的元素的位置,查找失败则返回0*/
Status PriorElem(SqList L,ElemType cur_e,ElemType &pre_e)   /* 若cur_e是L中的数据元素,且不是第一个,则pre_e返回它的前驱,否则失败,pre_e无定义*/

Status NextElem(L,cur_e,&next_e)   /*若cur_e是L中的数据元素,且不是第一个,则next_e返回它的后继,否则失败,next_e无定义*/

Status ListInsert(SqList &L,int i,ElemType e); /*在L中第i个位置之前插入一个新的数据e,L的长度加一*/

Status ListDelete(SqList &L,int i,ElemType &e); /*删除L的第i个数据元素,并用e返回其值,L的长度减一*/
  • 空线性表的创建:

先创建一个起始节点,因为是空表,所以将表中的数据长度设为零

Status InitList(SqList &L); /*构造一个空的线性表L*/
{
    L.elem = (ElemType *)malloc(sizeof(ElemType)*LIST_INIT_ZIZE); //动态内存分配
    if(!L.elem)
        exit(OVERFLOW); //内存分配失败
    L.length = 0; //初始化线性表长度为0
    L.listsize = LIST_INIT_ZIZE; //初始化线性表储存容量
}
  • 判断是否为空的线性表:

只需判断表中数据长度是否为零就行

Status ListEmpty(SqList L);  /*判断是否为空表*/
{
    if(L.length == 0) //线性表长度是否为0
        return TURE;
    else
        return FLASE;
}
  • 判断是否为满表:

只需判断表中数据个数是否已达到最大容纳量即可

Status ListFull(SqList L);  /*判断是否为满表*/
{
    if(L.length == L.listsize) //线性表长度是否已达到储存容量
        return TURE;
    else
        return FLASE;
}
  • 将线性表L重置为空表:

个人认为只需将表中数据个数都归零即可

Status ClearList(SqList &L);  /*将L重置为空表*/
{
    L.length = 0; //线性表长度归零
    return OK;
  • 销毁线性表:

将头节点置零,并将表中数据个数都置零,且表的数据容纳量也相应置零
,最后释放无用头节点

Status DestroyList(SqList &L); /*销毁线性表*/
{
    L.elem = NULL; //线性表的基址归0
    L.length = 0; //长度归零
    L.listsize = 0; //储存容量归零
    free(L.elem); //释放头结点
}
  • 返回线性表长度:

只需返回表中数据个数即可

Status ListLength(SqList L); /*线性表的长度*/
{
    return L.length; //返回线性表当前长度
}
  • 查找L中第i个元素,并用e表示其值

首先要判断i是否为表中元素,即判断i是否大于等于一且小于表的数据长度

Status GetElem(SqList L,int i,ElemType &e); /*查找L中第i个元素,并用e表示其值*/
{
    if(i < 1||i > L.length) //i小于一或i大于当前线性表长度
        return ERROR;
    e = *(L.elem + i - 1) //第i个元素的地址等于基址加i-1
        return OK;
}
  • 查找线性表L中满足函数的元素的位置:

从起始节点开始计数并判断节点是否满足相等关系,不满足则不断后移一位继续判断,直至满足相等关系,最后位置也必须满足是表中元素

Status LocateElem(SqList L,ElemType e) /*查找L中第一个与e满足关系相等的元素的位置,查找失败则返回0*/
{
    int i = 1; //i的初值为第一个元素的位置
    ElemType *p = L.elem; //p的初值为第一个元素的储存基址
    while(i <= L.length&&!(*compare)(*p++,e)) //不超过表的长度且未找到满足关系的元素
        ++i;
    if(i <= L.length) //i不超过表长
        return i;
    else
        return 0;
}
  • 返回查找到元素位置的前驱:

    取表的初始地址,然后从上一个函数取得该元素位置,因为要返回前驱,所以该元素不能为首元素,即该序列不为一,然后返回该元素前驱为初始地址加i减二

Status PriorElem(SqList L,ElemType cur_e,ElemType &pre_e)   /* 若cur_e是L中的数据元素,且不是第一个,则pre_e返回它的前驱,否则失败,pre_e无定义*/ 
{
    ElemType *p = L.elem; //p的初值为第一个元素的储存基址
    int a;
    a = LocateElem(L,cure); 
    if(!a||a == 1)  
        return ERROR;
    else
        per_e = *(L.elem + a -2); //用per_e来返回该元素的前驱
    return OK;
}
  • 返回查找元素位置的后继:

    取表的初始地址,然后从上一个函数取得该元素位置,因为要返回后继,所以该元素不能为尾元素,即该序列不为表中最后一个数据的序列,然后返回该元素后继为初始地址加i

Status NextElem(L,cur_e,&next_e)   /*若cur_e是L中的数据元素,且不是第一个,则next_e返回它的后继,否则失败,next_e无定义*/
{
    ElemType *p = L.elem; //p的初值为第一个元素的储存基址
    int a;
    a = LocateElem(L,cure); 
    if(!a||a != L.length)
        return ERROR;
    else
        next_e = *(L.elem + a) //用next_e来返回该元素的后继
}
  • 在L的第i个位置插入新元素,表长加一:

首先判断此时表的数据个数是否已达最大容量,是则增加容量,并分配新的起始地址,然后找到表的第i个位置起始地址加i减一,然后表中第i个位置之后的元素地址都后移一位,表中数据个数加一,并插入新元素

Status ListInsert(SqList &L,int i,ElemType e); /*在L中第i个位置之前插入一个新的数据e,L的长度加一*/
{
    ElemType *newbase,*p,*q;
    if(i < 1||i > L.length+1) //i小于一或i大于当前线性表长度+1
        return ERROR;
    if(L.length == L.listsize) //L当前长度等于储存容量,增加内存分配
    {
        newbase = (ElemType *)relloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType));//realloc对malloc申请的内存进行大小的调整
        if(!newbase)         //给一个已经分配了地址的指针重新分配空间,参数L.elem为原有的空间地址,之后的sizeof是重新申请的地址长度
            exit(OVERFLOW);       //储存分配失败
        L.elem = newbase;         //新基址
        L.listsize += LISTINCREMENT; //增加储存容量
    }
    p = L.elem + i - 1; //插入元素的位置
    for(q = L.elem + L.length - 1;q >= p;--q) 
    {
        *(q+1) = *q; //插入位置及其之后的元素右移
    }
    *p = e; //插入e
    ++L.length; //表长加一
    return OK;
}
  • 删除线性表L第i个位置的元素,表长减一:

先判断i是否为表中元素,是则将i之后元素全部左移一位,表长相应减一(注:只是元素左移。其容量依旧不变)

Status ListDelete(SqList &L,int i,ElemType &e); /*删除L的第i个数据元素,并用e返回其值,L的长度减一*/
{
    ElemType *p,*q;
    if(i < 1||i > L.length+1) //i小于一或i大于当前线性表长度+1
        return ERROR;
    p = L.elem + i - 1; //删除元素位置
    e = *p; //被删元素值赋给e
    q = L.elem + L.length - 1; //表尾元素位置
    for(++p;p <= q;++p)
    {
        *(p-1) = *p; //删除元素之后元素左移
    }
    --L.length; //表长减一
}
  • 主函数:

主要具体实现以上操作

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

struct list
{
    ElemType *elem; //存放数据元素的基址
    int length; //当前线性表的长度
    int listsize; //当前分配的储存容量
}SqList;



int main()
{
    SqList L;
    InitList(SqList &L); /*构造一个空的线性表L*/
    ElemType e;
    ElemType &pre_e,&next_e;
    int i;
    int choice;

    while(1)
    {
        printf("*************************************************\n");
        printf("*[1] 判断是否为空表   [2]判断是否为满表         *\n");
        printf("*[3] 将表L清空        [4] 销毁表L               *\n");
        printf("*[5] 查找L中第i个元素 [6]查找表中与e相等元素位置*\n");
        printf("*[7]与e相等位置的前驱 [8]与e相等位置的后继      *\n");
        printf("*[9]表L第i之前插入新数[10]删除L第i个元素        *\n");
        printf("*************** [0] 退出系统 ******************\n");
        printf("*************************************************\n");
        printf("请选择:  ");
        scanf("%d",&choice);
        switch(choice)
        {
            case 0: break;
            case 1: ListEmpty(L);  //判断是否为空表
            break;

            case 2: ListFull(L);  //判断是否为满表
            break;

            case 3: ClearList(L);  //将L重置为空表
            break;

            case 4: DestroyList(L); //销毁线性表
            break;

            case 5: printf("请输入i值\n"); 
                    scanf("%d",&i);
                    GetElem(L,i,e); //查找L中第i个元素,并用e表示其值
                    printf("%d\n",e);break;

            case 6: printf("请输入e\n");
                    scanf("%d",&e);
                    LocateElem(L,e) //查找L中第一个与e满足关系相等的元素的位置,查找失败则返回0
            break;

            case 7: printf("请输入e\n");
                    scanf("%d",&e);
                    PriorElem(L,cur_e,pre_e)   //若cur_e是L中的数据元素,且不是第一个,则pre_e返回它的前驱,否则失败,pre_e无定义
            break;

            case 8: printf("请输入e\n");
                    scanf("%d",&e);
                    NextElem(L,cur_e,next_e)   //若cur_e是L中的数据元素,且不是第一个,则next_e返回它的后继,否则失败,next_e无定义
            break;

            case 9: printf("请输入位置和数据 \n");
                    scanf("%d %d",&i,&e)
                    ListInsert(L,i,e); //在L中第i个位置之前插入一个新的数据e,L的长度加一 
            break;  

            case 10: printf("请输入位置\n");
                     scanf("%d",&i);
                     ListDelete(L,i,e); //删除L的第i个数据元素,并用e返回其值,L的长度减一
            break;
        }
    }
} 

以上就是几个最基本的线性表操作,不足的地方会继续完善,希望各位大佬指出不足!互相关注交流学习。

猜你喜欢

转载自blog.csdn.net/qq_42014895/article/details/80261495
今日推荐