学习数据结构(二)——顺序表与链表

目录

 

1.线性表

2.c++的表示


1.线性表

线性表是形式为数据元素的有序序列。长度可根据需求增加或减少,不仅可以访问数据元素,还可以进行插入、修改、删除等操作。线性表中存在唯一的第一个元素和最后一个元素,每个数据元素只有唯一前面一个和后面一个元素。线性表的顺序表示是一组地址连续的存储单元依次存储线性表中的数据元素。

为了克服顺序表插入和删除中需要移动大量元素的不足,采用链式结构存储线性表,链式结构不仅可以表示线性,也可以表示非线性。对于数据元素a_{i}来说,不仅需要存储数据域(本身的信息),还要存储指针域(后继数据元素的地址),由这两部分组成的存储映射每个节点只包括一个指针域,故也叫单向链表。单链表存取必须从头指针开始,且最后一个指针为NULL。有时可以在第一个数据元素前附加一个头结点。当尾指针指向头地址,则形成循环链表。注意:一个是线性结构,一个是链式结构。

为了克服单向链表的单向性缺点,则在每个结点又增设了一个前驱指针。

顺序表的存储空间是静态的,需要事先估计。而链表的是动态生成释放的;顺序表通常用一维数组表示。

2.c++的表示

vector、list、deque都可以用来存放线性表,选择原则如下:如果你需要高效的随即存取,而不在乎插入和删除的效率,使用vector;如果你需要大量的插入和删除,而不关心随即存取,则应使用list;如果你需要随即存取,而且关心两端数据的插入和删除,则应使用deque。

数组:分配的是静态空间,一般分配了就不可以改变,就像我们熟知的定义了一个数组,那么数组的长度就不可以改变了,我们也不可以进行越界访问,但是编译器不检查越界,这一点在我们编程的时候要尤为注意。vector:分配的是动态空间,即:我们发现在声明vector容器的时候也可以不指定容器的大小,vector是随着元素的加入,空间自动扩展的。但是,我们必须要负责任的肯定vector分配的空间是连续的,也就是支持数组中的下标随机访问,实际上vector的实现机制是:预留一部分空间,而且预留空间的大小是按一定比率增长的,如果空间不够用的话,要保证连续,就必须重新new一片空间,然后将原有元素移动到新空间,同时预留新的空间(并且新分配的空间比原来分配的空间),最后将原来的那部分空间释放掉。这样预留空间的好处就是不用每次向vector中加元素都重新分配空间。

线性表应具有如下功能的函数:

InitList(&L)构造一个空的线性表L
DestroyList(&L)销毁线性表L
IsEmpty(L)若L为空,返回真,否则返回假
Length(L)返回L中数据元素个数
GetElem(L,i,&e)用e返回第i个数据元素的值,1\leq i\leq ListLength(L)
LocateElem(L,e)返回第一个和e相等的数据元素的位序。否则,返回0

PriorElem(L,cur,&pre)

若cur是L的第一个数据元素,则操作失败,否则,pre为前驱值
NextElem(L,cur,&next)若cur是L最后一个数据元素,则操作失败,否则,next为后驱值
ListInsert(&L,i,e)在第i个位置之前插入新的数据元素e,长度为1,且1\leq i\leq length(L)+1
ListDelete(&L,i,&e)删除L中的第i个数据元素,用e返回,长度减1,且1\leq i\leq length(L)
ListTraverse(L)依次输出L的值

对应list中的函数有:(1)begin()和end():通过调用list容器的成员函数begin()得到一个指向容器起始位置的iterator,可以调用list容器的 end() 函数来得到list末端下一位置,相当于:int a[n]中的第n+1个位置a[n],实际上是不存在的,不能访问,经常作为循环结束判断结束条件使用。(2)push_back() 和push_front():使用list的成员函数push_back和push_front插入一个元素到list中。其中push_back()从list的末端插入,而 push_front()实现的从list的头部插入。(3)empty():利用empty() 判断list是否为空。(4)esize(): 如果调用resize(n)将list的长度改为只容纳n个元素,超出的元素将被删除,如果需要扩展那么调用默认构造函数T()将元素加到list末端。如果调用resize(n,val),则扩展元素要调用构造函数T(val)函数进行元素构造,其余部分相同。(5) clear(): 清空list中的所有元素。(6) front()和back(): 通过front()可以获得list容器中的头部元素,通过back()可以获得list容器的最后一个元素。但是有一点要注意,就是list中元素是空的时候,这时候调用front()和back()会发生什么呢?实际上会发生不能正常读取数据的情况,但是这并不报错,那我们编程序时就要注意了,个人觉得在使用之前最好先调用empty()函数判断list是否为空。(7)pop_back和pop_front():通过pop_back()删除最后一个元素,通过pop_front()删除第一个元素;序列必须不为空,如果当list为空的时候调用pop_back()和pop_front()会使程序崩掉。(8)assign():具体和vector中的操作类似,也是有两种情况,第一种是:l1.assign(n,val)将 l1中元素变为n个T(val)。第二种情况是:l1.assign(l2.begin(),l2.end())将l2中的从l2.begin()到l2.end()之间的数值赋值给l1。(9)swap():交换两个链表(两个重载),一个是l1.swap(l2); 另外一个是swap(l1,l2),都可能完成连个链表的交换。(10)reverse():通过reverse()完成list的逆置。(11) merge():合并两个链表并使之默认升序(也可改),l1.merge(l2,greater<int>()); 调用结束后l2变为空,l1中元素包含原来l1 和 l2中的元素,并且排好序,升序。其实默认是升序,greater<int>()可以省略,另外greater<int>()是可以变的,也可以不按升序排列。(12)list(n) 声明一个有n个元素的列表,每个元素都是由其默认构造函数T()构造出来的;list(n,val) 声明一个由n个元素的列表,每个元素都是由其复制构造函数T(val)得来的;list(first,last) 声明一个列表,其元素的初始值来源于由区间所指定的序列中的元素;list() 声明一个空列表;

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值