小猪的数据结构辅助教程——2.1 线性表中的顺序表

小猪的数据结构辅助教程——2.1 线性表中的顺序表

标签(空格分隔): 数据结构


本节学习路线图与学习要点

学习要点

  • 1.抽象数据类型(ADT)的概念,三要素:数据,数据元素间的关系和数据的操作
  • 2.线性表的特点:按照一条线排列的数据集合,1对1,除了首元和尾元,其他元素都有直接前驱和直接后继
  • 3.牢记线性表的存储结构,要理解并熟悉12个基本操作的逻辑,最好能徒手撕出代码
  • 4.求并集,顺序表的经典例子,必须掌握!

1.抽象的数据类型

简单点说:

抽象:有点像我们面向对象语言中的类的思想,将事物的共性抽取出来,形成属性和对应的方法!

数据类型:比如我们C中学的整型,浮点型等这些就是数据类型,就是具有同一性质的集合;

另外定义浮点类型是为了避免一些麻烦,比如保存2这个整数用浮点型就有点大材小用了~


2.线性表介绍以及顺序表的引入

从上面的存储结构,不难知道顺序表的三个属性:

存储空间的其实位置;最大存储容量listsize;当前长度length;


3.12个基本操作的代码实现

PS:别去死记代码,把逻辑掌握就好,不清楚自己列几个数据,画画图!


线性表的存储结构

#define MAXSIZE 20
#define INCREMENT 10
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0

//定义一个int数据类型的别名
//这里因为演示采用int,实际使用的通常是复合的数据类型
typedef int ElemType;
typedef int Status;
typedef struct{
    ElemType *elem;   //存储空间的起始地址
    int length;       //表的当前长度
    int listsize;     //表的总存储容量(以sizeof(ElemType)为单位)
}SqList;

1.构造空表

void InitList(SqList *L){
    L -> elem = (ElemType *)malloc(MAXSIZE * sizeof(ElemType));
    if(!L -> elem)exit(ERROR);
    L -> length = 0;
    L -> listsize = MAXSIZE;
}

步骤:

  • Step 1:申请表的存储空间,将空间的起始地址赋值给elem,

    然后通过判断elem是否为空,从而知道内存是否分配成功

  • Step 2:将表的当前长度length设置为0,将表的大小listsize设置为MAXSIZE

2.将表置为空表

void ClearList(SqList *L)
{
    L ->length = 0;
}

步骤:

只需将表长设置为空即可,很简单


3.判断表是否为空

//3)判断表是否为空
Status ListEmpty(SqList L)
{
    return L.length == 0?TRUE:FALSE;
} 

步骤:

只需判断表长是否为0即可


4.销毁表

//4)销毁表
void DestoryList(SqList *L)
{
    free(L ->elem);
    L ->elem = NULL;
    L ->length = 0;
    L ->listsize = 0;
} 

步骤:

  • Step 1:调用free方法释放L.elem所指向的内存空间
  • Step 2:将L.elem赋值为NULL
  • Step 3:将当前的表长以及表的存储容量设置为0

5.获得表中元素的数目

int ListLength(SqList L)
{
    return L.length;
}

步骤:

直接返回当前表长度即可


6.获得表中第i个元素的值

Status GetElem(SqList L,int i,ElemType *e)
{
    if(i < 1||i > L.length)return ERROR;
    e = *(L.elem + i - 1);
    return OK;
}  

步骤:

Step 1:先判断第i个位置是否合法

Step 2:将对应位置的值赋给e,另外这里减1是因为数组下标是从0开始算的,而我们看表是

从1开始算的,所以需要减一


7.查找表中是否有满足要求的元素

int LocateElem(SqList L,ElemType e,Status(*compare)(ElemType,ElemType))
{
    int i = 1;
    ElemType *p = L.elem;
    while(i < L.length && !compare(*p++,e))
    i++;
    if(i <= L.length) return i;
    else return 0;
}

步骤:

Step 1:定义变量i和指针p分别指向表中第1个元素和表的首地址

- Step 2:循环调用compare()函数与表中的元素进行比较

- Step 3:如果i <= length的话说明找到了,返回对应元素的序号

- Step 4:否则返回0,表示找不到满足要求的元素


8.返回某个节点的前驱

Status PriorElem(SqList L,ElemType choose,ElemType &Before){
    int i = 2;
    ElemType *p = L.elem + 1;
    while(i < L.length && *p != choose)
    {
        p++;
        i++;
    }
    if(i > L.length)return ERROR;
    else
    {
        Before = *--p;
        return OK;
    }
} 

步骤:

Step 1:首元是没有直接前驱的,所以i应该从2开始,所以P从L.elem + 1开始;

Step 2:循环查看数据元素在表中的位置,如果i > 表长表示找不到,返回ERROR;

Step 3:找到的话,通过*–p获得该元素的前驱的值赋值给before;


9.返回某个节点的后继

Status NextElem(SqList L,ElemType choose,ElemType *behind)
{
    int i = 1;
    ElemType *p = L.elem;
    while(i < L.length && *p != choose)
    {
        p++;
        i++;
    }
    if(i == L.length)return ERROR;
    else{
        behind = * ++p;
        return OK;
    }
} 

步骤:

和前驱那个差不多,不过要注意i == L.length就到头了,因为尾元是没有后继的!


10.往表中第i个位置插入元素

Status ListInsert(SqList *L,int i,ElemType e)
{
    ElemType *p,*q,*newbase;
    //判断插入位置是否合法
    if(i < 1 || i > L -> length + 1)return ERROR;
    //假如表满了的话,增加分配的空间
    if(L -> length == L -> listsize)
    {
        newbase = (ElemType *)realloc(L -> elem,(L -> listsize + INCREMENT)*sizeof(ElemType));
        if(!newbase)exit(ERROR);
        L ->elem = newbase;
        L ->listsize += INCREMENT;
    }
    //插入位置
    q = L ->elem + i - 1;
    //向右移,先移动最后一个
    for(p = L ->elem + L->length - 1;p >= q;--p)
    {
        *(p + 1) = *p;
    }
    * q= e;      //插入元素
    ++ L ->length;   //表长 + 1
    return OK;
}

步骤:


11.删除表中的第i个位置的元素

Status ListDelete(SqList *L,int i,ElemType *e)
{
    ElemType *p,*q;
    //判断删除的位置是否合法
    if(i < 1 || i > L ->length)return ERROR;
    //P指针指向删除位置,将要删除的元素赋值给e
    p = L ->elem + i - 1;
    e = *p;
    //q指针指向最后一个元素,从删除位置后的元素开始左移
    q = L ->elem + L ->length - 1;
    for(++p;p <= q;++p)
    {
        *(p - 1) = *p;
    }
    L ->length--; //表长-1
    return OK;
} 

步骤:


12.遍历表中的所有元素

void ListTraverse(SqList L,void(* visit)(ElemType))
{
    int i;
    ElemType *p = L.elem;
    for(i = 1;i < L.length;i++)
    {
        visit(*p++);
        printf("\n");
    }
}

步骤:

很简单,就是从第一个元素开始,指针后移动,依次调用visit()函数

实现表中元素的遍历而已


4.应用小示例:

问题

已知A,B两个顺序表中的元素是按从小到大排列的;现在要你求两个的并集C;

而且C中的元素也要按从小到大排序;不改变A和B中的数据!

是并集哦,就是C中不能有重复的元素

void UnionList(SqList La,SqList Lb,SqList *Lc)
{
    //1.定义指向表A,B表头,表尾的指针
    ElemType *la,*la_end,*lb,*lb_end,*lc;
    la = La.elem;
    lb = Lb.elem;
    la_end = La.elem + La.length - 1;
    lb_end = Lb.elem + Lb.length - 1;
    //2.为表C分配内存空间,大小为表A长度 + 表B的长度
    Lc ->listsize  = La.length + Lb.length;
    lc = Lc ->elem = (ElemType *)malloc(Lc ->listsize * sizeof(ElemType));
    if(!lc)exit(ERROR);
    //3.将表A和B中的元素进行合并,
    while(la <= la_end && lb <= lb_end)
    {
        if(*la <= *lb)*lc++ = *la++;
        else *lc++ = *lb++;
    }
    //4.假如有剩余的元素,要么是表A,要么是表B的
    while(la < la_end)*lc++ = *la++;
    while(lb < lb_end)*lc++ = *lb++;
    //5.接着要将C表中重复的元素删除掉,这里来两枚指针
    ElemType *p,*q;
    p = Lc ->elem;
    q = p;
    //6.循环,假如入指针p没有指向表尾
    while(p != (Lc ->elem + Lc ->length - 1))
    {
        //q指向p的后继元素,比较两数的值
        if(*p != *(++q))
        {
            p++;
            q = p;
        }
        //相等的话,删除q所指向的元素
        else
        {
            while(*p == *q);
        //  ListDelete(Lc,(p - Lc ->elem),e);
        }
    }
}

5.本节代码下载:

时间关系,明早回公司再贴出来哈~


时间: 2024-11-03 21:12:35

小猪的数据结构辅助教程——2.1 线性表中的顺序表的相关文章

小猪的数据结构辅助教程——2.7 线性表中的双向循环链表

小猪的数据结构辅助教程--2.7 线性表中的双向循环链表 标签(空格分隔): 数据结构 本节学习路线图与学习要点 学习要点: 1.了解引入双向循环链表的原因 2.熟悉双向循环链表的特点以及存储结构 3.掌握双向循环链表的一些基本操作的实现逻辑 4.掌握逆序输出双向循环链表元素逻辑 1.双向循环链表的引入 2.双向循环链表的存储结构 双向循环链表的特点: 上面也说了,空间换时间,比起循环链表只是多了一个指向前驱的指针 特点的话: 判断空表:L ->next = L -> prior = L; 存

小猪的数据结构辅助教程——2.4 线性表中的循环链表

小猪的数据结构辅助教程--2.4 线性表中的循环链表 标签(空格分隔): 数据结构 本节学习路线图与学习要点 学习要点: 1.了解单链表存在怎样的缺点,暴露出来的问题 2.知道什么是循环单链表,掌握单链表的特点以及存储结构 3.掌握循环链表的一些基本操作的实现逻辑,最好能手撕代码 1.循环单链表的引入 2.循环链表的特点以及存储结构 循环链表的特点: 上面也说了,比单链表稍微高比格一点的地方就是: 链表最后一个结点的指针域指向了头结点而已,这样形成所谓的环,就是循环单链表了,呵呵! 特点的话有:

小猪的数据结构辅助教程——2.2 线性表中的单链表

小猪的数据结构辅助教程--2.2 线性表中的单链表 标签(空格分隔): 数据结构 本节学习路线图与学习要点 学习要点: 1.理解顺序表以及单链表各自的有点以及缺点! 2.熟悉单链表的形式,对于头指针,头结点,尾结点,数据域和指针域这些名词要知道是什么! 3.熟悉单链表的结点结构 4.区分头指针与头结点! 5.熟悉创建单链表的两种方式:头插法和尾插法 6.了解单链表12个基本操作的逻辑 7.有趣的算法题:查找单链表的中间结点~ 1.单链表的引入(顺序表与单链表的PK) 2.单链表的结构图以及一些名

小猪的数据结构辅助教程——3.1 栈与队列中的顺序栈

小猪的数据结构辅助教程--3.1 栈与队列中的顺序栈 标签(空格分隔): 数据结构 本节学习路线图与学习要点 学习要点 1.栈与队列的介绍,栈顶,栈底,入栈,出栈的概念 2.熟悉顺序栈的特点以及存储结构 3.掌握顺序栈的基本操作的实现逻辑 4.掌握顺序栈的经典例子:进制变换的实现逻辑 1.栈与队列的概念: 嗯,本节要进行讲解的就是栈 + 顺序结构 = 顺序栈! 可能大家对栈的概念还是很模糊,我们找个常见的东西来拟物化~ 不知道大家喜欢吃零食不--"桶装薯片"就可以用来演示栈! 生产的时

小猪的数据结构辅助教程——2.5 经典例子:约瑟夫问题的解决

小猪的数据结构辅助教程--2.5 经典例子:约瑟夫问题的解决 标签(空格分隔): 数据结构 约瑟夫问题的解析 关于问题的故事背景就不提了,我们直接说这个问题的内容吧: 一堆人,围成一个圈,然后规定一个数N,然后依次报数,当报数到N,这个人自杀,其他人鼓掌!啪啪啪, 接着又从1开始报数,报到N又自杀-以此类推,直到死剩最后一个人,那么游戏结束! 这就是问题,而我们用计算机模拟的话,用户输入:N(参与人数),M(第几个人死),结果返回最后一个人! 类似的问题有跳海问题,猴子选王等,下面我们就以N =

小猪的数据结构辅助教程——3.2 栈与队列中的链栈

小猪的数据结构辅助教程--3.2 栈与队列中的链栈 标签(空格分隔): 数据结构 1.本节引言: 嗯,本节没有学习路线图哈,因为栈我们一般都用的是顺序栈,链栈还是顺带提一提吧, 栈因为只是栈顶来做插入和删除操作,所以较好的方法是将栈顶放在单链表的头部,栈顶 指针与单链表的头指针合二为一~所以本节只是讲下链栈的存储结构和基本操作! 2.链栈的存储结构与示意图 存储结构: typedef struct StackNode { SElemType data; //存放的数据 struct StackN

小猪的数据结构辅助教程——1.数据结构与算法绪论

小猪的数据结构辅助教程--1.数据结构与算法绪论 标签(空格分隔): 数据结构 本节学习路线图与学习要点 学习要点: 1.了解数据结构的相关概念 2.了解算法的相关概念 3.熟悉时间复杂度的计算 4.了解空间复杂度的概念,闰年表空间换时间的样例~ 1.什么是数据结构? 2.算法的叙述 3.时间复杂度计算的简单演示样例 数据结构预算法--时间复杂度分析实例

小猪的数据结构辅助教程——2.6 经典例子:魔术师发牌问题和拉丁方阵问题

小猪的数据结构辅助教程--2.6 经典例子:魔术师发牌问题和拉丁方阵问题 标签(空格分隔): 数据结构 本节引言: 本节继续带来的是循环链表的两个经典例子,分别是魔术师发牌问题和拉丁方阵问题! 1.魔术师发牌问题 问题描述: 魔术师利用一副牌中的13张黑桃牌,预先将他们排好后叠放在一起,牌面朝下.对观众说:"我不看牌,只数数就可以猜到每张牌是什么,我大声数数,你们听,不信?现场演示."魔术师将牌堆最上面的哪张排数为1,把他翻过来正好是黑桃A,将黑桃A从牌堆抽出放在桌子上,第二次数1.2

《数据结构、算法与应用》9.(C++实现顺序表)

最近在读<数据结构.算法与应用>这本书,把书上的习题总结一下,用自己的方法来实现了这些题,可能在效率,编码等方面存在着很多的问题,也可能是错误的实现,如果大家在看这本书的时候有更优更好的方法来实现,还请大家多多留言交流多多指正,谢谢 9. C++实现的线性表--顺序表 // // LinearList.h // LinearList // // Created by cc on 14-8-21. // Copyright (c) 2014年 cc. All rights reserved. /