进入大学一年了,今日终于有勇气写写随笔并展示出来了。

如有不足之处,请大家指正。

今日我想写的就是我对数据结构-线性表_顺序表的理解。


不BB了,进入正题!!!!!


数据结构中的逻辑结构分为线性结构和非线性结构,而线性表就属于线性结构。

线性结构是 n 个数据元素的有序(次序)集合,它有下列几个特征:

  1. 集合中必存在唯一的一个 "第一个元素";
  2. 集合中必存在唯一的一个 "最后的元素";
  3. 除最后元素之外,其它数据元素均有唯一的 "后继";
  4. 除第一元素之外,其它数据元素均有唯一的 "前驱"。

根据存储方式不同,线性表可以分为顺序表和链表:

  • 数据元素在内存中集中存储,采用顺序表示结构,简称 “顺序存储”;(类似于数组)
  • 数据元素在内存中分散存储,采用链式表示结构,简称 “链式存储”。(类似于C语言中的单链表)

枯燥的文字,读来索然无味,上张图看看。。。

一般线性表包含下列基本操作:

  • 初始化
  • 销毁
  • 重置为空表
  • 判断是否为空
  • 获取长度
  • 根据位置获取对应元素
  • 查找元素
  • 获取指定元素的前驱和后继元素
  • 插入元素
  • 删除元素
  • 遍历元素

接下来就用线性表来实现这些基本操作。


首先,我们需要定义一个线性表。

用宏INIT_SIZE定义线性表的初始长度,当存储空间不足时,用INCREMENT_SIZE来定义空间增量

#define INIT_SIZE 10        //初始化表长
#define INCREMENT_SIZE 5    //分配增

接下来定义结构体来作为存储结构,储存类型由Elemtype指定,这我就将其设为int类型

指针elem表示第一个元素存储位置,length表示当前储存元素个数,size表示表长

typedef int Elemtype;

/*
* 存储结构
*/
typedef struct
{
    Elemtype *elem;    //存储空间基址
    int length;        //当前长度
    int size;        //当前分配的表长大小
}SqList;

TRUE和FALSE两个宏表示判断结果是否为真,返回TRUE则为真,返回FALSE则为假。

OKERROR 两个宏是定义函数的执行结果,返回 OK 说明操作成功,返回 ERROR 说明函数执行失败。

Status 定义后,函数的返回值就不必写为 int,而是写成更容易让人理解程序含义的 Status

#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0

typedef int Status;


基本定义结束,就开始具体的来实现这些功能函数吧》》》》》》

初始化

使用 malloc 函数申请一个初始大小 INIT_SIZE 的线性表,如果未申请成功则返回NULL

/*
* 初始化一个空的线性表
*/
Status InitList(SqList *L)
{
    L->elem = (Elemtype *) malloc(INIT_SIZE * sizeof(Elemtype));
    if (!L->elem)
    {
        return ERROR; }

 L->length = 0;
    L->size = INIT_SIZE;
    return OK;
}


销毁

直接将储存空间释放掉,结构体其他两项置为0

/*
* 销毁线性表
*/
Status DestroyList(SqList *L)
{
    free(L->elem);
    L->length = 0;
    L->size = 0;
    return OK;
}


重置为空表

将length置为0,则表示没有储存元素。

/*
 * 清空线性表
 */
Status ClearList(SqList* L)
{
 L->length = 0;
 return OK;
}


判断是否为空

若length为0则无元素为空

/*
 * 判断线性表是否为空
 */
Status isEmpty(const SqList L)
{
 if (0 == L.length)  //为空则length为0
 {
  return TRUE;
 }
 else
 {
  return FALSE;
 }
}


获取长度

length即代表长度

/*
 * 获取长度
 */
Status getLength(const SqList L)
{
 return L.length;
}


根据位置获取对应元素

先判断查询位置是否在序列范围内,如果在,则直接取值

/*
 * 根据位置获取元素
 */
Status GetElem(const SqList L, int i, Elemtype* e)
{
 if (i < 1 || i > L.length)  //输入位置在序列外界
 {
  return ERROR;
 }
 *e = L.elem[i - 1];
 return OK;
}


查找元素

先封装一个函数判断两元素是否相等,再遍历比较,如果找到则直接返回位置退出循环,如果完全循环也没找到,则返回ERROR

(其实封装与不封装也没多大差别)

/*
 * 比较两个元素是否相等
 */
Status compare(Elemtype e1, Elemtype e2)
{
 if (e1 == e2)
 {
  return 0;
 }
 else if (e1 < e2)
 {
  return -1;
 }
 else
 {
  return 1;
 }
}

/*
 * 查找元素
 */
Status FindElem(const SqList L, Elemtype e)
{
 int i;
 for (i = 0; i < L.length; i++)
 {
  if (!(*compare)(L.elem[i], e))
  {
   return i + 1;
  }
 }
 if (i >= L.length)
 {
  return ERROR;
 }
}


获取指定元素的前驱和后继元素

与查询大致一样,只是第一个元素无前驱,最后一个元素无后继,循环时加入判断即可

/*
 * 查找前驱元素
 */
Status PreElem(const SqList L, Elemtype cur_e, Elemtype* pre_e)
{
 int i;
 for (i = 0; i < L.length; i++)
 {
  if (cur_e == L.elem[i])
  {
   if (i != 0)  //若是第一个则无前驱
   {
    *pre_e = L.elem[i - 1];
   }
   else
   {
    return ERROR;
   }
  }
 }
 if (i >= L.length)  //完全遍历也没找到
 {
  return ERROR;
 }
}

/*
 * 查找后继元素
 */
Status NextElem(const SqList L, Elemtype cur_e, Elemtype* next_e)
{
 int i;
 for (i = 0; i < L.length; i++)
 {
  if (cur_e == L.elem[i])
  {
   if (i < L.length - 1)  //若是最后一个则无后驱
   {
    *next_e = L.elem[i + 1];
    return OK;
   }
   else
   {
    return ERROR;
   }
  }
 }
 if (i >= L.length)     //完全遍历也没找到
 {
  return ERROR;
 }
}


插入元素

先判断插入位置是否在1-length+1范围内,再判断当前空间是否已满,是否需要扩容

如果是最后一个位置插入则直接插入,否则设定两个指针,第一个指针指向需要插入位置,第二个位置指向末尾,不断将元素向后移动,最后插入并记录当前长度。

/*
 * 插入元素
 */
Status InsertElem(SqList* L, int i, Elemtype e)
{
 Elemtype* nuw;
 if (i < 1 || i > L->length + 1)  //只能在序列区域及后一个插入
 {
  return ERROR;
 }
 if (L->length >= L->size)   //判断当前空间是否已满
 {
  nuw = (Elemtype*)realloc(L->elem, (L->size + INCREMENT_SIZE) * sizeof(Elemtype)); //追加空间
  if (!nuw)    //追加成功为不为NIULL
  {
   return ERROR;
  }
  L->elem = nuw;
  L->size += INCREMENT_SIZE;
 }
 if (i - 1 == L->length) {
  L->elem[L->length] = e;
 }
 else {
  Elemtype* p = &L->elem[i - 1];
  Elemtype* q = &L->elem[L->length - 1];
  for (; q >= p; q--)
  {
   *(q + 1) = *(q);
  }
  *p = e;
 }
 ++L->length;
 return OK;
}


删除元素

先判断想要删除元素,是否在序列范围内,如果在则记录值,再将后面元素依次向前移动

/*
 * 删除元素并返回其值
 */
Status DeleteElem(SqList* L, int i, Elemtype* e)
{
 if (i < 1 || i > L->length)  //不在范围之内
 {
  return ERROR;
 }
 Elemtype* p = &L->elem[i - 1];
 *e = *p;
 for (++p; p < &L->elem[L->length]; p++)
 {
  *(p - 1) = *(p);
 }
 --L->length;
 return OK;
}


遍历元素

不断循环遍历元素。

/*
 * 访问元素
 */
void visit(Elemtype e)
{
 cout << e << " ";
}
/*
 * 遍历线性表
 */
Status TraverseList(const SqList L)
{
 int i;
 for (i = 0; i < L.length; i++)
 {
  visit(L.elem[i]);
 }
 return OK;
}

最后直接上代码,整体感受一下

#include<iostream>
#include<cstdlib>

using namespace std;


#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INIT_SIZE 10        //初始化表长
#define INCREMENT_SIZE 5    //分配增量

typedef int Status;
typedef int Elemtype;

/*
 * 存储结构
 */
typedef struct
{
    Elemtype* elem;    //存储空间基址
    int length;        //当前长度
    int size;        //当前分配的表长大小
}SqList;

/*
 * 初始化一个空的线性表
 */
Status InitList(SqList* L)
{
    L->elem = (Elemtype*)malloc(INIT_SIZE * sizeof(Elemtype)); //分配空间
    if (!L->elem)            //分配成功不为空
    {
        return ERROR;
    }
    L->length = 0;
    L->size = INIT_SIZE;
    return OK;
}

/*
 * 销毁线性表
 */
Status DestroyList(SqList* L)
{
    free(L->elem);            //c语言释放空间
    L->length = 0;
    L->size = 0;
    return OK;
}

/*
 * 清空线性表
 */
Status ClearList(SqList* L)
{
    L->length = 0;
    return OK;
}

/*
 * 判断线性表是否为空
 */
Status isEmpty(const SqList L)
{
    if (0 == L.length)        //为空则length为0
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

/*
 * 获取长度
 */
Status getLength(const SqList L)
{
    return L.length;
}

/*
 * 根据位置获取元素
 */
Status GetElem(const SqList L, int i, Elemtype* e)
{
    if (i < 1 || i > L.length)        //输入位置在序列外界
    {
        return ERROR;
    }
    *e = L.elem[i - 1];
    return OK;
}

/*
 * 比较两个元素是否相等
 */
Status compare(Elemtype e1, Elemtype e2)
{
    if (e1 == e2)
    {
        return 0;
    }
    else if (e1 < e2)
    {
        return -1;
    }
    else
    {
        return 1;
    }
}

/*
 * 查找元素
 */
Status FindElem(const SqList L, Elemtype e)
{
    int i;
    for (i = 0; i < L.length; i++)
    {
        if (!(*compare)(L.elem[i], e))
        {
            return i + 1;
        }
    }
    if (i >= L.length)
    {
        return ERROR;
    }
}

/*
 * 查找前驱元素
 */
Status PreElem(const SqList L, Elemtype cur_e, Elemtype* pre_e)
{
    int i;
    for (i = 0; i < L.length; i++)
    {
        if (cur_e == L.elem[i])
        {
            if (i != 0)        //若是第一个则无前驱
            {
                *pre_e = L.elem[i - 1];
            }
            else
            {
                return ERROR;
            }
        }
    }
    if (i >= L.length)        //完全遍历也没找到
    {
        return ERROR;
    }
}

/*
 * 查找后继元素
 */
Status NextElem(const SqList L, Elemtype cur_e, Elemtype* next_e)
{
    int i;
    for (i = 0; i < L.length; i++)
    {
        if (cur_e == L.elem[i])
        {
            if (i < L.length - 1)        //若是最后一个则无后驱
            {
                *next_e = L.elem[i + 1];
                return OK;
            }
            else
            {
                return ERROR;
            }
        }
    }
    if (i >= L.length)                    //完全遍历也没找到
    {
        return ERROR;
    }
}

/*
 * 插入元素
 */
Status InsertElem(SqList* L, int i, Elemtype e)
{
    Elemtype* nuw;
    if (i < 1 || i > L->length + 1)        //只能在序列区域及后一个插入
    {
        return ERROR;
    }
    if (L->length >= L->size)            //判断当前空间是否已满
    {
        nuw = (Elemtype*)realloc(L->elem, (L->size + INCREMENT_SIZE) * sizeof(Elemtype));    //追加空间
        if (!nuw)                //追加成功为不为NIULL
        {
            return ERROR;
        }
        L->elem = nuw;
        L->size += INCREMENT_SIZE;
    }
    if (i - 1 == L->length) {
        L->elem[L->length] = e;
    }
    else {
        Elemtype* p = &L->elem[i - 1];
        Elemtype* q = &L->elem[L->length - 1];
        for (; q >= p; q--)
        {
            *(q + 1) = *(q);
        }
        *p = e;
    }
    ++L->length;
    return OK;
}

/*
 * 删除元素并返回其值
 */
Status DeleteElem(SqList* L, int i, Elemtype* e)
{
    if (i < 1 || i > L->length)        //不在范围之内
    {
        return ERROR;
    }
    Elemtype* p = &L->elem[i - 1];
    *e = *p;
    for (++p; p < &L->elem[L->length]; p++)
    {
        *(p - 1) = *(p);
    }
    --L->length;
    return OK;
}

/*
 * 访问元素
 */
void visit(Elemtype e)
{
    cout << e << " ";
}

/*
 * 遍历线性表
 */
Status TraverseList(const SqList L)
{
    int i;
    for (i = 0; i < L.length; i++)
    {
        visit(L.elem[i]);
    }
    return OK;
}

/*
 * 主函数测试
 */
int main()
{
    SqList L;
    if (InitList(&L))
    {
        Elemtype e;
        cout << "init_success" << endl;
        int i;
        for (i = 0; i < 10; i++)
        {
            InsertElem(&L, i + 1, i);
        }
        TraverseList(L/*, visit*/);
        cout << "length is " << getLength(L) << endl;
        if (GetElem(L, 1, &e)) {
            cout << "The first element is " << e << endl;
        }
        else
        {
            cout << "element is not exist" << endl;
        }
        if (isEmpty(L))
        {
            cout << "list is empty" << endl;
        }
        else
        {
            cout << "list is not empty" << endl;
        }
        cout << "The 5 at " << FindElem(L, 5) << endl;
        PreElem(L, 6, &e);
        cout << "The 6's previous element is " << e << endl;
        NextElem(L, 6, &e);
        cout << "The 6's next element is " << e << endl;
        DeleteElem(&L, 1, &e);
        cout << "delete first element is " << e << endl;
        cout << "list:";
        TraverseList(L);
        if (DestroyList(&L))
        {
            cout << endl << "destroy_success" << endl;
        }
    }
}

今日分享到此结束,感觉及其之好,期待下一次。。。fighting!!!!



12-24 23:32