STL源码剖析------------Vector和List数据结构的特点

这里,我将分别描述Vector和List的数据结构特点,以及一些函数的操作特点,然后再总结一下二者之间的区别

Vector的数据结构特点

Vector的数据安排以及操作方式,与array非常相似,二者之间唯一的差别在于空间的运用的灵活性,array是静态空间,一旦配置了就不能改变,要重新换一个大一点的区间,而Vector则在配置空间时预留一定的空闲空间,实现动态扩容

并且这里使用size来表示已使用空间的大小;capacity表示总容量大小(end_of_storage-start),也就是说,这里再在vector中会留有空间来实现动态扩充;

Vector维护的是一个连续的线性空间,所以不论元素类型如何,Vector的迭代器都可以实现比如operator++,operator--,operator+=,operator+,operator- 等操作,从而Vector支持随机存取,因此提供的迭代器是Random Access Iterators

这里Vector用了三个迭代器指针:

iterator start;        //表示目前使用空间的头
iterator finish;          //表示目前使用空间的尾
iterator end_of_storage;        //表示目前可用空间的尾

 接下来就是一些函数比如erase,insert,push_back这些操作的特点:

我们知道这里在Vector中是有预留空间的,当capacity>size时,那么push_back操作就是常数时间,

{
    finish=value;
    ++finish;
}

如果capacity==size,那么就需要重新申请一个连续的内存,大小为capacity=2*size,然后将原来的数据复制到这里来,释放原来的空间,很明显,这里就不再是常数的时间了,而是线性时间;

上面介绍的和insert操作要求是一样的,就不在赘述;

然后是erase操作,当删除一个区间的数据时,因为这个是连续存储,所以就需要将区间后面的数据复制到前面来,和删除区间的数据接上,变成连续的,你会发现,那么原来后面的位置数据还是在啊,没事,因为我改变了finish的指针地址,所以后面的数据就是无用的,push时刷新即可。

注:

你会发现,当原来尺寸不够时,重新换连续内存的时候,那么原来的迭代器就失效了,因此这里要注意,还有erase后,原来的迭代器所指的当前位置,就是那个区间的下一个了;

List的数据结构及特点

list设计中,是有两个部分,因此需要分开设计。

typedef ListNode* ListNodeP;

template<class T>
class ListNode
{
public:
	ListNode();
	~ListNode();
private:
T data;
ListNodeP Next;
ListNodeP Prev;
};


template<class T>
class List:public ListNode
{
public:
	List();
	~List();
	
};

一个是list节点的设置,因为list这里是双向链表,那么节点就必须得有next和prev,以及节点的运算符++等等;然后就是继承节点类的上层,即list类,其中定义了一些函数,用list作为数据结构,来实现一些算法,包括push,pop,erase,insert,sort等等;

 List的迭代器:

List不再能够像Vector一样以普通指针作为迭代器,因为其节点不保证在存储空间中连续存在,这个很重要,也就是说节点的所分配的内存并不是连续的;

由于STL List是一个双向链表,从而迭代器必须具备前移和后移的能力;从而List提供的是一个Bidirectional Iterators;

由于List里面每个节点都是一块地址,从而删除一个节点,那么还在的节点,其迭代器并不会失效,就连erase也只是删除的那个节点的迭代器失效;

注:

这里SGI List不仅是一个双向链表,而且还是一个环状链表,在这里,它使用一个节点node,使得它链接了begin和end;

template<class T,class Alloc=alloc>
class List:public ListNode
{
public:
	List();
	~List();
private:
    ListNodeP node;    //只要一个指针,便可表示整个环状双向链表
};

iterator begin() {return node->next;}
iterator end() {return node;}

从这个迭代器可以看出,这里的node是多出来,用来链接最开始的和结尾的;

其他的没啥可说的,但是List的sort需要说一下,因为list并不是随机迭代器,而STL的sort(),只接受RamdonAccessIterator ;

因此这里采用了归并排序,说实话,刚开始,我看到代码是懵的,这tm写的是啥呀,但是看了别人博客中关于这个算法的动态图的展示,我才知道它想干啥,我只想说,牛逼!

这里,就不展示书上写的了,我把leetcode中写的链表的排序,贴出来;

/**
 * Definition for singly-linked list.
 * struct ListNode {
 *     int val;
 *     ListNode *next;
 *     ListNode(int x) : val(x), next(NULL) {}
 * };
 */
class Solution {
public:
 
    
    ListNode* split(ListNode* node,int step)
    {
        for(int i=1;node&&i<step;++i){      //只将当前节点与后面分离
            node=node->next;  
        }
        if(!node)  return NULL;
        ListNode *tail=node->next;
        node->next=NULL;
        return tail;//总时返回下一个节点,但是将上一段隔离
    }
    
    ListNode* merge(ListNode* left,ListNode* right,ListNode* head)
    {
        ListNode* cur=head;
        while(left&&right)
        {
            if(left->val>right->val)
            {
                cur->next=right;
                cur=cur->next;
                right=right->next;
                
            }
            else
            {
                cur->next=left;
                cur=cur->next;
                left=left->next;
            }
        }
        cur->next=((left)?left:right);
        while(cur->next)    cur=cur->next;
        return cur;
    }
    
    
    ListNode* sortList(ListNode* head) {
        if(!head||!head->next)  return head;
        int sz=0;
        ListNode *dummy=new ListNode(0);
		dummy->next = head;  //制作一个上节点,将上节点的next作为首节点,传入
        ListNode*cur=head;
        while(cur)
        {
            cur=cur->next;
            ++sz;
        }
        ListNode* left;
        ListNode* right;
        ListNode* tail;
       for(int step = 1; step < sz; step <<= 1){
			cur = dummy->next;
			tail = dummy;
			while(cur){
                left=cur;
                right=split(left,step);
                cur=split(right,step);
                tail=merge(left,right,tail);    
            }
        
       }
        
        return dummy->next;
    }
};

Vector和List在删除的时候是有区别的,因为vector是连续的空间,从而在插入或删除的时候,很可能原来的空间就失效了,因此迭代器就失效了,需要一块新的空间,而List在插入的时候或删除的时候,只有当前节点会失效,他们每个节点都是独立的,只不过用数据结构连接起来。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值