表:c++ 数组和链表(图解)

1表 是什么?

表中的第一个元素是A,而最后一个元素是Ax-1。我们将不定义A的前驱元,也不定义Ax-;的后继元。元素A,在表中的位置( position)为i。为了简单起见,我们在讨论中将假设表中的元素是整数,但一般说来任意的复杂元素也是允许的(而且很容易由类模板来处理)。

1.1表 由数组实现

一片连续的储存空间实现 表 如图:

 优点:

1.数组实现使得printList以线性时间执行,而findxth则花费常数时间,这是最好的结果

缺点

2.插入和删除的花费却有可能是昂贵的,这取决于插入和删除发生的位置。在最坏的情况下,在位置0(换句话说是在表的前面)插入需要将整个数组后移--个位置以空出空间来;而删除第-一个元素则需要将表中的所有元素前移·个位置,因此这两种操作的最坏情况为O(N)。平均来看,这两种运算都需要移动表的一半的元素,因此仍然需要线性时间。另-方面,如果所有的操作都发生在表的末尾,就不需要移动任何元素,那么添加和删除的操作都花费O(1)的时间。

1.2表 由链表实现

链表不是一个连续的储存空间

 缺点:

为了执行printList ()或find(x),我们只要从表的第一个结点开始然后用next链遍历该表即可。与数组实现--样,这种操作显然是花费线性时间的,但是这个常数可能比用数组实现时要大。findKth操作不如数组实现时的效率高; findKth(i)花费O(i)的时间并以明显的方式遍历链表而完成。
优点:

删除:修改一个next就行啦

 插入:

 假设链接到链表前面的链接存在,那么,添加或删除第一项的特殊情况对应常量的时间。至于在链表的末尾添加(在最后一项后添加新项)的特殊情况,如果链接到最后项的链接存在的话,也是消耗常量的时间。这样,典型的链表保持至表的两端的链接。删除最后一项有点麻烦,因为必须找到最后项前面的项,更改其next链接到nullptr,然后更新这个保持为最后一项的链接。在经典的链表里每个结点存储指向下一结点的链接,但是没有提供关于上一个结点的任何信息。

双向链表:

 

2.STL中的向量和表

表(Abstract Data Type)ADT有两个流行的实现。

vector给出了表ADT的可增长的数组实现。使用vector的优点在于其在常量的时间里是可索引的。缺点是插入新项或删除已有项的代价是昂贵的,除非是这些操作发生在vector的末尾。

list提供了表ADT的双向链表实现。使用list的优点是,如果变化发生的位置已知的话,插入新项和删除已有项的代价是很小的。缺点是list不容易索引。

vector和list两者在查找时效率都很低

int size() const;//返回容器元素个数
void clear();//删除
bool empty();//判断容器没有元素

void push_back(const object& x)
void pop_back();

const object &back() const;
const object &front() const;

//list 实现的是双向链表 允许在前端

void pop_front()
void push_front()

//
object& operator[](int ind)//不包含边界检测
object& at(ind)//包含边界检测
int capacity()//返回容量
void reserve(int new capacity)

2.1迭代器

一些表的操作,例如那些在表的中部进行插入和删除的操作,需要位置标记

在STL中,通过内置类型iterator来给出位置

2.1.1获取迭代器

iterator begin();//返回第一个

iterator end() //返回第二个
 

2.1.2迭代器方法

itr++和++itr:推进迭代器itr至下一个位置。前缀和后缀两种形式都是允许的。

*itr:返回存储在迭代器itr指定位置的对象的引用。返回的引用或许能、或许不能被修改(后面我们将讨论这些细节)。

itrl==itr2:如果itr1和itr2都指向同一个位置就返回true,否则,返回false。

itr1 !=itr2:如果itr1和itr2都指向不同位置就返回true,否则,返回false。

2.1.3需要迭代器的操作

iterator insert( iterator pos,const object & x):添加x到表中迭代器pos所指向的位置之前的位置。这对list是常量时间操作,但是对vector则不是。返回值是一个指向插入项位置的迭代器。

iterator erase( iterator pos):删除迭代器所给出位置的对象。这对list来说是常量时间操作,但对vector则不是。返回值是调用之前pos所指向元素的下一个元素的位置。这个操作使pos失效。pos不再有用,因为它所指向的容器变量已经被删除了。

iterator erase( iterator start, iterator end):删除所有的从位置start开始、直到位置end(但是不包括end)的所有元素。注意,整个表的删除可以调用c.erase( c.begin( ) . c.end ( ) ) .

 2.1.4 const_iterator

*itr的结果不只是迭代器指向的项的值,也是该项本身。

template<typename Container,typename object>
void change(Container &c,const Object& newValue)
{
  using auto itr=c.begin();
  while(itr!=c.end())
   *itr++=newValue;
}

如果这段代码是合法的话,那么list的定常性就完全没有任何意义了,因为改变起来太容易了。这段代码是非法的,并且不会被编译。STL提供的解决方案是每一个集合不仅包含嵌套的iterator类型,也包含嵌套的const_iterator类型。iterator和const_iterator之间的主要区别是: const_iterator的operator*返回常量引用,这样const_iterator的*itr就不能出现在城值语句的左边。
 

template<typename Container>
void  removeEveryOtherItem(Container& lst)
{
 auto itr=lst.begin();
 while(itr!=lst.end())
{
  itr=lst.earse(itr);
  if(itr!=erase())
   ++itr;
}
}

3.4 数组的实现 -vector

3.4.1c++的数组特性

数组就是指向块内存的指针变量;实际的数组的大小必须由程序员单独确定。

内存块可以通过new[]来分配,但是相应地也就必须用delete[]来释放。

内存块的大小不能改变(但是可以定义一个新的具有更大内存块的数组,并且用原来的数组来将其初始化,然后原来的内存块就可以释放了)。

3.4.2 vetcor

(1) vector将仍然是基本数组(通过一个指针变量来指向分配的内存块)。数组的容量和当前的数组项数目存储在vector里。

(2) vector将通过实现“三大函数”,为复制构造函数和operator=提供深复制,同时也提供析构函数来回收基本数组。

(3) vector将提供resize例程来改变vector的大小(通常是更大的数);提供reserve例程来改变vector的容量(通常是更大的数)。容量的改变是通过为基本数组分配一个新的内存块,然后复制旧内存块的内容到新块中,再释放旧块的内存来实现的。()

(4) vector将提供operator[]的实现(正如1.7.2节中所提到的,operator[]典型的实现有访问函数和修改函数两个版本)。

(5) vector将提供基本的例程,例如size、empty、clear(它们是典型的一行例程)、back、pop_back和push_back。如果大小和容量都是一样的话,push_back例程将调用reserve来增大vector的容量。

(6) vector将支持嵌套的iterator和const_iterator类型,并且提供关联的begin和end方法。

3 表   链表的实现

(1) List类本身。包含连接到表两端的链接、表的大小以及-一系列的方法。

(2) Node类。该类看起来像是私有的嵌套类。一个结点包含数据和用来指向其前和其后的结点的指针,以及适当的构造函数。

(3) const_iterator类。该类抽象了位置的概念,是一个公有的嵌套类。const_iterator存储指向当前结点的指针,并且提供基本迭代器操作的实现,以及所有的重载操作符,例如=、==、!=和++。

(4) iterator类。该类抽象了位置的概念,是一个公有的嵌套类。除了operator*操作返回所指向项的引用,而不是该项的常量引用的功能外,iterator具有与const_iterator相同的功能。--个重要的技术点是iterator可以用于任何需要使用const_iterator的例程里,反之则不是。换句话说,iterator就是const_iterator。

插入:

template<typename object>
struct Node
{
 object data;
 Node* prev;
 Node* next;
 Node( const object & d = object(),
 Node *p = NULL,
 Node *n = NULL ): data (d),  prev(p) ,next(n)
 { }
};


iterator insert(iterator itr,const Object& x)
{
   Node *p=itr.current;//确定位置
   theSize++;
   return iterator(p->pre=p->pre->next=new Node(x,p->pre,p));

   
}

 Node* newnode=new Node(x,p->prev,p)//1,2

p->prev=p->prev->next=newnode//;

删除:

 p->prev->next=p->next;

p->next->prev=p->prev

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值