STL源码详解

article/2025/9/14 1:25:19

STL详解

  • STL介绍
  • 空间配置器
    • 一级空间配置器
    • 二级空间配置器
  • 序列式容器
    • vector
    • list
    • deque
  • 适配器
    • stack
    • queue
    • heap
    • priority_queue
  • 关联式容器
    • set
    • multiset
    • map
    • multimap
  • 非标准容器
    • hash_set(unordered_set)
    • hash_multiset(unordered_multiset)
    • hash_map (unordered_map)
    • hash_multimap(unordered_multimap)
  • 常见的面试问答
    • 1、说说 vector 和 list 的区别
    • 2、map 和 set 有什么区别
    • 3、unordered_map和map 说说区别


STL介绍

空间配置器

一级空间配置器

二级空间配置器

序列式容器

vector

vector是动态空间,随着元素的加入,它的内部机制会自动扩充空间以容纳新元素。因此vector的运用对于内存的合理利用与运用的灵活性有很大的帮助。
在这里插入图片描述
通过分析 vector 容器的源代码不难发现,它就是使用 3 个迭代器(可以理解成指针)来表示的:
注意:iterator 是普通的指针
iterator statrt指向vector 容器对象的起始字节位置,即是第一个元素;
iterator finish指向当前最后一个元素的下一个位置
iterator end_of_storage指向整个 vector 容器所占用内存空间的末尾字节。
如图 演示了以上这 3 个迭代器分别指向的位置

在这里插入图片描述
如图 演示了以上这 2个迭代器分别指向的位置

在此基础上,将 3 个迭代器两两结合,还可以表达不同的含义,例如:
size() :finish - start 可以用来表示 vector 容器中目前已被使用的内存空间;
end_of_storage - finish 可以用来表示 vector 容器目前空闲的内存空间;
capacity() :end_of_storage - start 可以用表示 vector 容器的容量。

vector的迭代器模拟实现

typedef T* Iteratot;
typedef T* const_Iteratot;Iteratot cend()const {return final_end;}Iteratot cbegin()const {return start;}//begin()返回的是vector 容器对象的起始字节位置;//end()返回的是当前最后一个元素的末尾字节;Iteratot end() {return final_end;}Iteratot begin() {return start;}

vector的扩容reserve()

	void reserve(size_t n) {if (n > capacity()) {T* temp = new T  [n];//把start中的数据拷贝到temp中size_t size1 = size();memcpy(temp, start, sizeof(T*) * size());start = temp;final_end = start + size1;finally = start + n;}}

注意
vector的容量capacity == 大小size时,如果再向vector添加新元素,那么vector需要扩容,扩容过程分为三步:
1、完全丢弃原来的内存空间,开辟分配新的内存空间,大小一般是原来的2倍(1.5倍,编译器不同分配大小可能不同)。
2、将原来的内存空间数据按顺序全部拷贝到新的内存空间。
3、将原来的内存空间释放掉。
这也就解释了,为什么 vector 容器在进行扩容后,与其相关的指针、引用以及迭代器可能会失效的原因,后续会讲失效的原因。

此外,如果对象中涉及到资源管理时,千万不能使用memcpy进行对象之间的拷贝,因为memcpy是浅拷贝,否则可能会引起内存泄漏甚至程序崩溃。

vector的push_back()、pop_back()

		void push_back(const T&var) {if (final_end ==finally) {size_t newcode = capacity() == 0 ? 4 : capacity() * 2;reserve(newcode);}*final_end = var;++final_end;void pop_back() {final_end--;}

在插入新的元素前,先判断容器是否有空闲空间(根据capacity == size),当容器没有空闲空间时,若容器的容量capacity = 0,则开辟分配4字节的大小,若容量不为0,则分配原来容量的2倍。

对insert()插入时迭代器失效刨析

	Iteratot insert(Iteratot iterator,const T&var) {assert(iterator <= final_end && iterator >= start);//先保存插入值的迭代器的位置size_t pos = iterator - start;//扩容,造成迭代器失效,但可以使用pos解决失效问题if (final_end == finally) {size_t newcode = capacity() == 0 ? 4 : capacity() * 2;reserve(newcode);	}//插入操作auto it = final_end;//将插入位置的后面元素均向后移动while (it >= start+pos) {*(it+1)=*it;it--;}//将值插入到该位置*iterator = var;final_end++;//返回该位置的值return iterator;}

对erase()数据删除时迭代器失效刨析

	Iteratot erase(Iteratot iterator) {assert(iterator <= final_end && iterator >= start);auto it = iterator;//删除,将后面的元素均往前移动while (it <final_end) {*it = *(it+1);it++;}final_end--;//返回的是删除元素的下一个迭代器//比如:1,2,3,4,5,6    需要删除3 ,则返回的是4的迭代器return iterator;}

由于erase()返回的是删除元素的下一个迭代器,故使得当前的迭代器失效。
问题呈现:

#include<iostream>
#include<vector>
using namespace std;int main(){int a[] = {1, 4, 3, 7, 9, 3, 6, 8, 3, 3, 5, 2, 3, 7};vector<int> arr(a, a + sizeof(a)/sizeof(int));auto it = arr.begin();while(it != arr.end()){if(*it == 3){arr.erase(it);cout << *it << endl;}it++;}for(vector<int>::iterator itor = arr.begin(); itor != arr.end(); itor++){cout << * itor << "  ";}return 0;
}

在这里插入图片描述
解决方案:其实就是将获取返回的迭代器,或将迭代器–。

#include<iostream>
#include<vector>
using namespace std;int main(){int a[] = {1, 4, 3, 7, 9, 3, 6, 8, 3, 3, 5, 2, 3, 7};vector<int> arr(a, a + sizeof(a)/sizeof(int));auto it = arr.begin();//方法一:while(it != arr.end()){if(*it == 3){arr.erase(it--);}it++;}//方法二:/*while(it != arr.end()){if(*it == 3){it = arr.erase(it);}elseit++;}*/for(vector<int>::iterator itor = arr.begin(); itor != arr.end(); itor++){cout << * itor << "  ";}return 0;
}

list

list:双向环形链表。它是一种物理存储单元上非连续、非顺序的存储结构,但也是一种序列式容器,因为每个节点都包含两个指针,前指针和后指针,将整个链表中的节点连接起来,在逻辑上是连续的。
前面讲到的vector是连续线性存储容器,虽然在随机访问上效率很高,但插入和删除的效率一般较低,因为每一次对非末尾进行插入和删除,都会导致数据的移动或扩容。
而list正是和vector相反,由于list在物理存储上非连续线性,所以它随机访问效率很低,但插入和删除效率却很高,因为每一次插入和删除只需要改变某节点前后指针的指向即可。
根据源码刨析去分析:
链表节点的定义:

template<typename T>
struct __list_node{typedef void* list_node_pointer;//设计的不理想,在4.9版本改为了__list_node*list_node_pointer prev;list_node_pointer next;T data;
};

链表的迭代器定义:

template<typename T,class Ref,class Ptr>
struct __list_iterator{typedef __list_iterator<T,T&,T*>   	 iterator;typedef __list_iterator<T,Ref,Ptr>   self;typedef __list_node<T>*      		 link_type;//迭代器的类别:双向迭代器typedef bidirectional_iterator_tag	iterator_category;typedef T                  value_type;typedef T&                 reference;typedef value_type*        pointer;//俩个迭代器之间的距离,ptrdiff_t : unsigned longtypedef ptrdiff_t		   difference_type;typedef size_t             size_type;link_type node; //成员//构造函数__list_iterator(link_type x = nullptr):node(x){}.....//先省略成员函数
}

链表的定义:

    template<typename T,class Alloc = alloc>//按照 list_node为单位分配内存,只分配一个元素大小的内存class list{protected:typedef __list_node<T> list_node;public:typedef list_node*         link_type;public://迭代器typedef __list_iterator<value_type> iterator;private:link_type node; // 只要一个指针,便可表示整个环状双向链表.............//为了更清晰的看list的定义,先省略其他的函数}

示图:
在这里插入图片描述
注意:图中的end()指向位置,它是一个空白节点,使得整个链表遵循前闭后开。
list的成员函数:

iterator begin() {//返回一个迭代器//调用__list_iterator<value_type>(link_type x)构造函数临时创建一个return (link_type)((*node).next);}iterator end(){return node;}bool empty(){return node->next == node;}size_type size(){size_type result = 0;distance(begin(),end(),result);//全局函数,计算两个迭代器之间的距离return result;}reference front(){return *begin();}reference back(){return *(--end());}

list内部提供的transfer迁移操作:

//将[first,last)内的所有元素移动到position之前
void transfer(iterator position ,iterator first, iterator last)
{if(position != last){//改变某些节点的指针指向//...}
}

在它的基础上为splice、sort、merge、reverse等奠定了良好的基础。
splice

//将x接合于position 所指位置之前的,x必须不同于*this
void splice(iterator position,list& x){}
//将同一个list的元素i接合到position 所指位置之前的
void splice(iterator position,list& ,iterator i){}
//将[first,last)的元素i接合到position 所指位置之前的,但position不能在[first,last)内
void splice(iterator position,list& ,iterator first,iterator last){}

merge

//将x合并到*this身上。两个lists的内容都必须经过递增排序
void merge(list<T,Alloc>& x){}

最后的注意:list的插入操作insert和splice接合操作都不会导致原有的list迭代器失效,不像vector的插入和删除操作都可能造成原有迭代器失效,因为vector插入操作可能会进行扩容,开辟新的存储空间,释放原有的旧空间,而list插入只会分配一个元素大小的空间,删除操作只会使得被删除的元素的迭代器失效。

deque

deque:双端队列。vector是单向开口的连续线性空间, deque 则是一种双向开口的连续线性空间,准确的是:deque是分段连续空间,维持其“整体连续”的假象。所谓双向开口,意思是可以在头尾两端分别做元素的插人和删除操作,如下图所示。vector当然也可以在头尾两端进行操作(从技术观点),但是其头部操作效率奇差,无法被接受。
在这里插入图片描述
deque 和vector的最大差异,一在于deque允许于常数时间内对起头端进行元素的插入或移除操作,二在于deque没有所谓容量(capacity)观念,因为它是动态地以分段连续空间组合而成,随时可以增加一段新的空间并链接起来。换句话说,像vector那样“因旧空间不足而重新配置一块更大空间,然后复制元素,再释放旧空间”这样的事情在 deque是不会发生的。也因此,deque没有必要提供所谓的空间保留(reserve)功能。
deque的主控
deque 采用一块所谓的map (注意,不是 STL的map容器)作为主控。这里所谓map是一小块连续空问,其中每个元素(此处称为一个节点,node)都是指针,指向另一段(较大的)连续线性空间,称为缓冲区。缓冲区才是deque的储存空间主体。SGI STL允许我们指定缓冲区大小,默认值0表示在元素大小不超过512字节时,将使用(512 / 一个元素的大小)bytes的缓冲区,超过512字节则一个缓冲区存储一个元素。
在这里插入图片描述
queue的定义

template <class T,class Alloc = alloc,size_t BufSiz = 0>
class deque{
public:typedef T value_type;typedef value_type* pointer;...
public:typedef __deque_iterator<T,T&,T*,BufSiz> iterator;
protected:typedef pointer* map_pointer;//它是个二级指针T**,指向的一块连续空间map,map存储着指向另一块空间的指针(也称缓冲区)map_pointer	map;//表现的第一个节点iterator start;//表现最后一个节点iterator finish;size_type map_size;
protected://两个专属的空间配置器//每次配置一个元素大小空间typedef simple_alloc<value_type,Alloc> data_allocator;//每次配置一个指针大小,为push_back、push_front、构造等操作提供的配置器,需要配置一个map大小的空间typedef simple_alloc<pointer,Alloc> map_allocator;
};

在这里插入图片描述
注意:map的设计很巧妙,当map满载时候,需要寻找一块更大的空间作为map,新的map会将原空间的数据拷贝过来,这些数据对称存储在新的map,这也是有利于后面增加新的缓冲区。
queue的迭代器
前面提到了deque本身其实是分段连续的空间,它的每个元素的物理地址不一定连续的,可能存储在不同的缓冲区中,那它对外声称连续性空间的任务都落在了迭代器的设计上面,即迭代器的operator++和operator–。
它的设计难点主要在于跨缓冲区操作,每次操作前都必须能够指出操作对象在哪个分段连续空间内(缓冲区),还必须判断是否达到了缓冲区的边界,若达到了边界需要跳跃到上一个/下一个缓冲区。为了能够正确的跳跃缓冲区,迭代器必须也有个主控来控制map,因为它定位哪一块缓冲区。

template <class T,class Ref,class Ptr,size_t BufSiz>
struct __deque_iterator{typedef __deque_iterator<T,T&,T*,BufSiz>	iterator;...//迭代器都必须自行撰写五个必要的迭代器相应型别。typedef random_access_iterator_tag	iterator_category;...typedef T** map_pointer;T*	cur;//指向缓冲区的当前元素T*	first;//缓冲区的左边界T*	last;//缓冲区的右边界map_pointer	node;//控制缓冲区的跳跃(主控)//缓冲区大小,能够存放多少个T类型的元素static size_t	buffer_size() {return __deque_buf_suze(BufSize,sizeof(T));}
};

注意:__deque_buf_suze()也是一个全局函数,它的定义如下:

//当 n != 0时,缓冲区的大小由n来决定
//当 n == 0时,且元素类型的大小 sz < 512 bytes时,缓冲区大小 = 512 / sz
//当 n == 0时,且元素类型的大小 sz >= 512 bytes时,缓冲区大小 = 1(每个缓冲区只放入一个元素)
inline size_t __deque_buf_suze(size_t n,size_t sz)
{return n != 0 ? n : (sz < 512 ? size_t(512 / sz) : size_t(1));
}

在这里插入图片描述
迭代器的主要操作:operator+=(最主要),operator[]
operatot+= 它实现了随机存取,迭代器可以直接跳跃n个距离

self& operator+=(difference_type n)
{//偏移量difference_type offset = n + cur - first;//判断是否在同一个缓冲区移动if(offset >= 0 && offset < difference_type(buffer_size());{//同一块缓冲区cur += n;}else{difference_type node_offset = offset > 0 ? offset / difference_type(buffer_size()) : -difference_type((-offset-1) / buffer_size())-1;//切换到正确的节点位置set_node(node + node_offset);//切换到正确的元素位置cur = first + (offset - difference_type(buffer_size()));}return *this;
}
//设置下一个缓冲区位置
void set_node(map_pointer new_node)
{node = new_node;first = *new_node;last = first + difference_type(buffer_size());
}

这里有必要讲一下insert和erase操作:

//erase(iterator pos)删除某个位置的元素
首先判断该位置的左右元素个数,left > right时
将right个元素向左移动一个位置,将pos移动到最右端
然后进行pop_back(),反之同理
//erase(iteratot first,iterator last)删除某区间的元素
首先判断该区间的元素左右元素个数
移动它们覆盖清除的区间的元素数据
移动完毕之后调用析构。
//insert(iterator pos,const value_type& x)
如果插入的时最前端,调用push_front
如果插入的是最后端,调用push_back
如果都不是,则判断该位置的前后元素个数
将在最前端/最后端push_front()/push_back()一个front()/back()的值
将它们向前/后移动一个位置
最后pos的位置腾空出来,直接插入pos即可。

适配器

stack

stack 是﹒种先进后出〔First In Last Out,FILO)的数据结构。它只有一个出口,形式如图4-18所示。stack 允许新增元素、移除元素、取得最顶端元素。但除了最顶端外,没有任何其它方法可以存取stack 的其它元素,换言之,stack不允许有遍历行为。
将元素推人 stack的操作称为push,将元素推出stack 的操作称为pop.
在这里插入图片描述
以某种既有容器作为底部结构,将其接口改变,使之符合“先进后出”的特性,形成一个 stack,是很容易做到的.deque是双向开口的数据结构,若以deque为底部结构并封闭其头端开口,便轻而易举地形成了一个stack。因此,SGI STL便以 deque 作为缺省情况下的 stack底部结构,stack 的实现因而非常简单,源代码十分简短,本处完整列出。
由于 stack 系以底部容器完成其所有工作,而具有这种“修改某物接口,形成另一种风貌”之性质者,称为adapter(配接器),因此,STL stack 往往不被归类为container (容器),而被归类为container adapter.
注意:stack没有迭代器,stack不提供遍历、随机访问等操作,只能在最顶端插入删除、访问元素。
stack默认底层结构使用deque,但list也是可以的。

queue

queue 是一种先进先出(First In First Out,FIFO)的数据结构。它有两个出口,形式如图4-19所示。queue 允许新增元素、移除元素、从最底端加入元素、取得最顶端元素。但除了最底端可以加入、最顶端可以取出外,没有任何其它方法可以存取queue的其它元素。换言之,queue不允许有遍历行为。
将元素推人queue的操作称为push,将元素推出queue的操作称为pop.
在这里插入图片描述
以某种既有容器为底部结构,将其接口改变,使其符合“先进先出”的特性,形成一个queue,是很容易做到的.deque是双向开口的数据结构,若以 deque 为底部结构并封闭其底端的出口和前端的人П,便轻而易举地形成了一个queue。因此,SGI STL便以deque 作为缺省情况下的queue 底部结构,queue 的实现因而非常简单,源代码十分简短,本处完整列出.

由于queue系以底部容器完成其所有工作,而具有这种“修改某物接П,形成另一种风貌”之性质者,称为adapter(配接器),因此,STL queue往往不被归类为container(容器),而被归类为container adapter。

注意:queue没有迭代器,queue所有元素的进出都必须符合“先进先出”的条件,只有queue顶端的元素,才有机会被外界取用。queue 不提供遍历功能,也不提供迭代器。也可以使用list作为底层结构,但效率比不上deque。

heap

heap并不归属于STL容器组件,它是个幕后英雄,扮演priority queue的助手。顾名思义,priority queue 允许用户以任何次序将任何元素推人容器内,但取出时一定是从优先权最高(也就是数值最高)的元素开始取。binarymax heap正是具有这样的特性,适合作为 priority queue 的底层机制。
在这里插入图片描述

堆的分类:最大堆和最小堆
最大堆:它的每一个节点的键值比子节点大或等于,故最大键值的节点是根节点。
最小堆:它的每一个节点的键值比子节点小或等于,故最大键值的节点是根节点。
主要的heap操作:
注意:heap操作都是在vector或array操作,array不能动态变化,所以它的push_heap()执行后和原的heap一样,因为push_heap默认数组尾部是新增的元素。

//将vector或array建立堆,默认为最大堆
1make_heap()
//向堆加入新元素总是在完全二叉树中最下层的叶子节点从左到右填补,这样的顺序也即是插入到vector尾部
//默认新元素插入到vector的尾端,则向上调整堆
2push_heap()

在这里插入图片描述

//将根节点和尾端节点交换,向下调整堆,注意没有删除最大值的节点
//只是将它放在了vector尾端。故可以利用这个特性完成sort_heap()操作
3pop_heap()

在这里插入图片描述

//利用了pop_heap()特性,循环遍历执行pop_heap操作,完成了降序排序
4sort_heap()

在这里插入图片描述

priority_queue

顾名思义,priority_queue是一个拥有权值观念的queue,它允许加入新元索、移除旧元索、审视元素值等功能。由于这是一个queue,所以只允许在底端加入元素,并从顶端取出元素,除此之外别无其它存取元素的途径。
priority_queue带有权值观念,其内的元素并非依照被推入的次序排列,而是自动依照元素的权值排列(通常权值以实值表示)。权值最高者,排在最前面。
缺省情况下priority-queue系利用一个max-heap + vector 完成的。
在这里插入图片描述
priority_queue的主要操作

//数据成员:
vector<T> c;	//底层容器
Compare comp;	//比较大小的标准bool empty()  const { return  c.empty(); }size_type size() const { return c.size(); }const_reference top() const { return c.front(); }//前面讲push_heap()是默认vector末尾元素是新增的,现在push()需要先将元素push_back()
void push(const value_type& x){ c.push_back(x);push_heap(c.begin(),c.end(),comp);} 
//pop_heap()是将根节点和尾端元素交换位置,并没有删除,故现在需要在pop_heap()之后进行pop_back()
void pop() { pop_heap(c.begin(),c.end(),comp); c.pop_back();}

priority_queue的测试

#include <iostream>
#include <algorithm>
#include <queue>	//头文件 
#include <vector>
using namespace std;int main()
{vector<int> arr;arr.push_back(5);arr.push_back(8);arr.push_back(2);arr.push_back(6);arr.push_back(1);for(auto& x : arr) cout << x << " ";	// 5 8 2 6 1cout << endl;//priority_queue<int,vector<int>,greater<int>> 最小堆//priority_queue<int,vector<int>,less<int>> 最大堆priority_queue<int> que(arr.begin(),arr.end());cout << "que.size() = " << que.size() << endl;	// 5cout << "que.top() = " << que.top() << endl;	// 8que.pop();	 //删除根节点,并进行堆调整,之后的que.top()是下一个最大值 cout << que.top() << endl;	// 6 cout << que.size() << endl;	// 4return 0;
}

注意:priority_queue也是一种适配器,以某种特点的容器作为底层容器,更应该称为容器的适配器,它没有迭代器,不能随机访问,只能访问顶端元素(优先级最高)。

关联式容器

set

multiset

map

multimap

非标准容器

hash_set(unordered_set)

hash_multiset(unordered_multiset)

hash_map (unordered_map)

hash_multimap(unordered_multimap)

常见的面试问答

1、说说 vector 和 list 的区别

1) vector, 连续存储的容器,动态数组,在堆上分配空间 ;
底层实现:数组。
如果没有剩余空间了,则会重新配置原有元素个数的两倍空间,然后将原空间元素通过复制的方式初始化新空间,再向新空间增加元素。
扩容的三部曲:
1、分配更大的新空间
2、移动数据
3、释放旧空间
适用场景:经常随机访问,且不经常对非尾节点进行插入删除。

2)list,双向环形链表,在堆上分配空间,每插入一个元素都会分配空间(一个元素大小的空间),每删除一个元素都会释放空间。
底层:双向环形链表,内部含有一个空白节点,满足符合前闭后开原则。
访问:随机访问性能很差,只能快速访问头尾节点。
适用场景:经常插入删除大量数据
3) vector在中间节点进行插入删除会导致内存拷贝,list不会。
4) vector一次性分配好内存,不够时才进行2倍扩容;list每次插入新节点都会进行内存申请。
5) vector拥有一段连续的内存空间,因此支持随机访问,如果需要高效的随即访问,而不在乎插入和删除的效率,使用vector。
6)list拥有一段不连续的内存空间,如果需要高效的插入和删除,而不关心随机访问,则应使用list。
7)vector的迭代器是一个普通指针,而list是一个双向型别的迭代器。

2、map 和 set 有什么区别

1) map和set都是C++的关联容器,其底层实现都是红黑树(RB-Tree)。
2) map中的元素是key-value(关键字—值)对:关键字起到索引的作用,值则表示与索引相关联的数据;set与之相对就是关键字的简单集合,set中每个元素只包含一个关键字。
3) set的迭代器是const的,不允许修改元素的值data;map允许修改data,但不允许修改key。
4) map支持下标操作,set不支持下标操作。map可以用key做下标。

3、unordered_map和map 说说区别

内部实现机理

map: map内部实现了一个红黑树,该结构具有自动排序的功能,因此map内部的所有元素都是有序的,红黑树的每一个节点都代表着map的一个元素,因此,对于map进行的查找,删除,添加等一系列的操作都相当于是对红黑树进行这样的操作,故红黑树的效率决定了map的效率。
unordered_map: unordered_map内部实现了一个哈希表,因此其元素的排列顺序是杂乱的,无序的
优缺点以及适用场景

map
优点:
有序性,这是map结构最大的优点,其元素的有序性在很多应用中都会简化很多的操作
红黑树,内部实现一个红黑书使得map的很多操作在的时间复杂度下就可以实现,因此效率非常的高
缺点:
适用处,对于那些有顺序要求的问题,用map会更高效一些
空间占用率高,因为map内部实现了红黑树,虽然提高了运行效率,但是因为每一个节点都需要额外保存父节点,孩子节点以及红/黑性质,使得每一个节点都占用大量的空间。

unordered_map
优点:
因为内部实现了哈希表,因此其查找速度非常的快
缺点:
适用处,对于查找问题,unordered_map会更加高效一些,因此遇到查找问题,常会考虑一下用unordered_map,哈希表的建立比较耗费时间。


http://chatgpt.dhexx.cn/article/7CBYokQT.shtml

相关文章

STL源码刨析

1. STL概述 STL起源&#xff1a; 为的就是复用性的提升&#xff0c;减少人力资源的浪费&#xff0c;建立了数据结构与算法的一套标准。 STL所实现的、是依据泛型思维架设起来的一个概念结构。这个以抽象概念〔 abstract concepts&#xff09;为主体而非以实际类(classes&…

侯捷——STL源码剖析 笔记

侯捷——STL源码剖析 笔记 1.总览 1.STL六大部件之间的关系 在下图中&#xff0c;我们使用了如下&#xff1a; 1.一个容器vector 2.使用vector时&#xff0c;使用分配器分配内存 3.使用vi.begin(),vi.end()即迭代器&#xff0c;作为算法的参数 4.使用count_if算法 5.使用仿函…

【GeoServer】CentOS7.x上GeoServer的安装部署

GeoServer 是 OpenGIS Web 服务器规范的 J2EE 实现&#xff0c;利用 GeoServer 可以方便的发布地图数据&#xff0c;允许用户对特征数据进行更新、删除、插入操作&#xff0c;通过 GeoServer 可以比较容易的在用户之间迅速共享空间地理信息。 GeoServer 主要特性&#xff1a;兼…

部署GeoServer

部署GeoServer 部署方式很多总&#xff0c;这里介绍两种 安装包安装 默认已经安装了Tomcat&#xff1a; Tomcat9.0安装教程 下载war包 使用geoserver的war包在tomcat中部署&#xff0c;从官网中下载对应版本的war GeoServer官网地址 安装 解压软件 将war包复制到tomcat…

GeoServer安装部署

介绍&#xff1a; Geoserver 是一个开源的地理空间数据服务器,它可以发布和编辑地理数据。这里简单介绍 Geoserver 的部署安装和后台运行。 它的主要功能包括: 管理空间数据&#xff1a;GeoServer可以连接各种空间数据源,包括文件(SHP、CSV等)、数据库(PostGIS,Oracle,SQL Ser…

geoserver 创建只读用户

目录 一、创建只读角色 一、创建新账号&#xff0c;将新账号添加到只读角色中 三、配置权限 四、校验 一、创建只读角色 1、选择Security->Users,Groups,Roles->Roles->Add new role 2、输入名称&#xff0c;parent role 不选&#xff08;防止获取到父级角色的权限…

GeoServer学习笔记-01GeoSever运行编译

一、运行 1. 下载GeoServer GitHub仓库地址&#xff1a;https://github.com/geoserver/geoserver 2.本地代码工具打开项目 在idea里&#xff0c;文件->新建->来自现有的源代码项目&#xff0c;选择项目的pom文件加载项目。 3.idea编译环境设置 &#xff08;1&#xff09;…

java geoserver_本机搭建GeoServer

最近尝试试本机搭建GeoSrver的服务&#xff0c;分享一下搭建安装教程&#xff0c;总共分为以下几步&#xff1a; 下载Java的GDK&#xff0c;添加环境变量 GeoServer 依赖于Java的环境&#xff0c;劝告一定要下载 1.8(8)的版本&#xff0c;虽然现在已经更新到 14&#xff0c;但是…

Geoserver中跨域问题解决

场景 GeoServer简介、下载、配置启动、发布shapefile全流程(图文实践)&#xff1a; GeoServer简介、下载、配置启动、发布shapefile全流程(图文实践)_霸道流氓气质的博客-CSDN博客 上面安装Geoserver的基础下。 使用ajax请求GeoJson时提示跨域 注&#xff1a; 博客&#x…

GeoServer发布服务,中文标注乱码

1.问题&#xff1a; 发布的矢量数据源 shapefiles&#xff0c;中文标注显示乱码问题&#xff0c;如下图所示&#xff1a; 2.解决办法 编辑矢量数据源&#xff0c;DBF文件的字符集&#xff0c;改为GB2312。 显示正常&#xff1a;

geoserver热图

1.参考 GeoServer发布Heatmap - wenglabs - 博客园 Rendering Transformations — GeoServer 2.21.x User Manual 2.下载 GeoServer 及wps插件&#xff0c;该插件gs:heatmap支持热图样式 3.发布测试shp geoserver热图测试数据-其它文档类资源-CSDN下载 4、添加热图样式&…

Geoserver添加mongoDB数据源

文章目录 概述操作1. 添加mongodb 插件2. 添加数据源3. 添加数据3. 发布服务 概述 本文讲述如何在geoserver中添加mongoDB作为数据源&#xff0c;并发布图层。 操作 1. 添加mongodb 插件 在浏览器输入地址下载页面&#xff0c;下载mongodb插件。 [外链图片转存失败,源站可能…

Geoserver介绍2:geoserver页面介绍

目录 Geoserver介绍2&#xff1a;geoserver页面介绍 一、打开登录geoserver的web管理页面 二、 页面左侧&#xff0c;功能介绍 &#xff08;一&#xff09;、关于和状态 &#xff08;二&#xff09;、数据 1、图层预览 2、工作区 3、数据存储 4、图层 5、图层组 6、样…

geoserver

geoserver 总 —— 配置建议数据源选择QGIS配色相关透明度设置 安装配置Windowsjdk环境配置geoserver安装安装一体化包&#xff08;基于 jetty 推荐&#xff09;基于tomcat安装 Linux&#xff08;centos7.9&#xff09;基于 tomcat 安装 geoserver性能调优JVM内存调整启用 CORS…

geoserver离线地图服务搭建和图层发布

前言 项目用到了GIS地图&#xff0c;在浏览器进行展示。起初使用了在线的高德地图。高德官网api丰富&#xff0c;且都是中文&#xff0c;很好用&#xff0c;也很方便。但是随着需求的变更&#xff0c;项目环境也从互联网变成了内网环境。所以高德地图就不能再用了&#xff0c;…

GIS系列(四)GeoServer的介绍和用法

《WebGIS快速开发教程》写好啦_WebGIS小智的博客-CSDN博客 首先,GeoServer是一个地图服务器。 关于地图服务器,其实和普通服务器没啥区别,就是专门用来发布地图的。 实际上,如果你的项目是前后端结合的话,可以不需要地图服务器。 你可以在后端配合Geotools,postgis等…

如何使用GeoServer发布WMS服务

如何使用GeoServer发布地图 作者&#xff1a;郜庆科 本文所采用的系统为Windows 10 64bit操作系统&#xff0c;使用FireFox浏览器 一、安装配置Java的SDK 1、 安装Java Development Kit (JDK) 8&#xff0c;java开发环境&#xff0c;需要先到Java的官方网站下载合适自己的安…

geoserver系列(一)tomcat安装及geoserver安装

由于项目的需要&#xff0c;最近一直使用geoserver作为基础的地图数据服务&#xff0c;查找过很多的资料&#xff0c;也走过很多的弯路&#xff0c;现在想对之前所踩过的坑和一些基本操作做一个geoserver系列的总结。 目前&#xff0c;我所使用的是tomcatgeoserver的形式进行基…

Linux+GIS学习笔记之三——GeoServer的安装与配置

注意&#xff1a;安装GeoServer时&#xff0c;服务器不需要提前安装Tomcat&#xff0c;只需要安装完整的GeoServer即可。 1.下载GeoServer 这里使用的是Stable 2.11.1 &#xff08;下载地址&#xff09; 2.上传文件 使用xftp将下载的zip文件上传到root文件夹中 3.解压GeoSe…

GeoServer入门(一):发布第一个WMS图层

本章主要讲述如何下载和安装使用GeoServer服务器&#xff0c;介绍了GeoServer的管理界面&#xff0c;并演示了发布地理数据的简单流程。 主要从以下几个方面展开叙述&#xff1a; 下载和安装GeoServerGeoServer管理界面发布图层数据的流程 1. 下载和安装GeoServer GeoServer…