STL源码剖析 list概述

目录

list的节点(node)

list迭代器

 list 的构造和内存管理

list 的元素操作

  •  list相较于vector连续的线性空间就显得很复杂,他的存储空间是不连续的,好处是每次插入和删除一个元素的时候,只需要配置或者释放一个元素的空间

  • 插入和删除十分的方便

list的节点(node)

  • list 本身和list的节点是不同的结构,需要分开设计
  • list节点结构是一个双向的链表
template <class T>
struct __list_node{typedef void* void_pointer;void_pointer prev;   //指针的类型是void*,其实可以将其设定为 __list_node<T>void_pointer next;   T data;
};

list迭代器

  • list迭代器不能像vector一样使用普通的指针,因为考虑到内存分配的不连续性,list的迭代器必须有能力指向list的的节点,并正确的进行递增、递减、取值(获取成员节点的数据值)、成员的存取(取用的是节点的成员)等操作
  • 因为list的迭代器具备前移和后移的能力,所以使用Bidirectional iterators
  • list的插入和接合操作(splice)都不会造成原有的list迭代器失效,vector不可以,因为vector插入操作可能造成记忆体的重新配置,会导致原有的迭代器失效
  • list删除元素(erase)也只有指向被删除元素的那个迭代器会失效,其余的迭代器不会受到任何的影响

  •  list迭代器设计如下
//list的迭代器设计
template <class T,class Ref,class Ptr>
struct __list_iterator{typedef __list_iterator<T,T&,T*>    iterator;typedef __list_iterator<T,Ref,Ptr>  self;typedef std::bidirectional_iterator_tag iterator_category;typedef T value_type;typedef Ptr pointer;typedef Ref reference;typedef __list_node<T>* link_type;typedef std::size_t size_type;typedef ptrdiff_t difference_type;link_type node;//迭代器内部需要一个普通的指针,指向list节点//constructor__list_iterator(){}__list_iterator(link_type x):node(x){}__list_iterator(const iterator& x):node(x.node){}bool operator==(const self& x) const{return (node == x.node);}bool operator!=(const self& x) const{return (node != x.node);}//以下对迭代器取值 取得的是节点的数据值reference operator*() const {return (*node).data;}//以下是对迭代器的成员进行存取 (member access) 运算子的标准做法pointer operator->() const {return &(operator*());}//对迭代器进行加一 前进一个节点self& operator++(){node = (link_type)((*node).next);}self operator++(int){self tmp = *this;++*this;return tmp;}//对迭代器进行减一 后退一个节点self& operator--(){node = (link_type)((*node).prev);}self operator--(int){self tmp = *this;--*this;return tmp;}
};

list的数据结构

  • SGI list不仅仅是双向链表 还是一个环状双向链表,只需要一个指针就可以完成整个链表的遍历
//list的迭代器设计
template <class T,class Ref,class Ptr>
struct __list_iterator{typedef __list_iterator<T,T&,T*>    iterator;typedef __list_iterator<T,Ref,Ptr>  self;typedef std::bidirectional_iterator_tag iterator_category;typedef T value_type;typedef Ptr pointer;typedef Ref reference;typedef __list_node<T>* link_type;typedef std::size_t size_type;typedef ptrdiff_t difference_type;link_type node;//迭代器内部需要一个普通的指针,指向list节点//constructor__list_iterator(){}__list_iterator(link_type x):node(x){}__list_iterator(const iterator& x):node(x.node){}bool operator==(const self& x) const{return (node == x.node);}bool operator!=(const self& x) const{return (node != x.node);}//以下对迭代器取值 取得的是节点的数据值reference operator*() const {return (*node).data;}//以下是对迭代器的成员进行存取 (member access) 运算子的标准做法pointer operator->() const {return &(operator*());}//对迭代器进行加一 前进一个节点self& operator++(){node = (link_type)((*node).next);}self operator++(int){self tmp = *this;++*this;return tmp;}//对迭代器进行减一 后退一个节点self& operator--(){node = (link_type)((*node).prev);}self operator--(int){self tmp = *this;--*this;return tmp;}//让指针node刻意指向尾端的一个空白节点,node节点便会符合STL对于前开后闭区间的要求,成为list迭代器iterator begin(){return (link_type)(*node->next);}iterator end(){return node;}bool empty()const{return node->next == node;}size_type size()const{size_type result = 0;std::distance(begin(),end(),result);return result;}//取头部节点的内容(元素数值)reference front(){return *begin();}//取尾节点的内容(元素数值)reference back(){return *(--end());}
};
//list 环状双向链表设计如下
template <class T,class Alloc> //缺省使用alloc作为配置器
class list{
protected:typedef __list_node<T> list_node;
public:typedef list_node* link_type;
protected:link_type node; //只需要一个指针,便可以循环遍历整个环状的双向链表
};

 list 的构造和内存管理

  • 具体内容见代码注释
//list 环状双向链表设计如下
template <class T,class Alloc> //缺省使用alloc作为配置器
class list{protected:typedef __list_node<T> list_node;//专属空间配置器 每次配置一个节点的大小
public:typedef list_node* link_type;typedef simple_alloc<list_node,Alloc>list_node_allocator;//list_node_allocator(n) 表示分配n个节点空间,以下四个函数分别用来配置、释放、构造、销毁一个节点
protected://配置一个节点并返回link_type get_node(){return list_node_allocator::allocate();}//释放一个节点link_type put_node(){return list_node_allocator::deallocate();}//产生(配置并构造)一个节点 带有元素数值link_type create_node(const T& x){link_type p = get_node();Chy::allocator<T>::construct(p->data,x); //全局函数 构造/析构基本工具return p;}//销毁 (析构并释放) 一个节点void destroy_node(link_type p){Chy::allocator<T>::destroy(&p->data);  //全局函数 构造/析构基本工具}public://构造函数//产生一个空的链表list(){empty_initialize();} //产生一个空的链表
protected:link_type node; //只需要一个指针,便可以循环遍历整个环状的双向链表void empty_initialize(){node = get_node();  //配置一个节点空间,令node指向它node->next = node;  //令node头尾指向自己  不设置元素值node->prev = node;  }
};

  •  当使用push_back()将新的元素插入到list的尾端的时候 ,这个函数内部调用的是insert();

list 的元素操作

//清除所有的节点(整个链表)
template <class T,class Alloc>
void list<T,Alloc>::clear() {link_type cur = (link_type)node->next; //begin()while (cur != node){   //遍历每一个节点link_type tmp = cur;cur = (link_type)cur->next;destroy_node(tmp); //销毁、析构释放一个节点}//恢复node的原始状态node->next = node;node->prev = node;
}//清除数值为value的所有元素
template<class T,class Alloc>
void list<T,Alloc>::remove(const T &value) {typedef typename __list_iterator<T,T&,T*>::iterator iterator;iterator first = __list_iterator<T,T&,T*>::begin();iterator last = __list_iterator<T,T&,T*>::end();while (first != last){iterator next = first;++next;if (*first == value){__list_iterator<T,T&,T*>::erase(value);first = next;}}
}//移除数值相同的连续元素,注意:只有"连续并且相同的元素",才会被删除只剩一个
template <class T,class Alloc>
void list<T,Alloc>::unique() {typedef typename __list_iterator<T,T&,T*>::iterator iterator;iterator first = __list_iterator<T,T&,T*>::begin();iterator last = __list_iterator<T,T&,T*>::end();if (first == last){return; //空的链表  什么都不做}iterator next = first;while(++next != last){       //遍历每一个节点if (*first == *next){    //如果这个区段中存在相同的元素__list_iterator<T,T&,T*>::erase(next); //移除之} else{first = next;        //调整指针}next = first;            //修正区段范围}
}
  • list是一个双向的环状链表,只需要处理边界条件,在头部和尾部插入和删除的操作几乎是一样的
  • 移除(erase) 某个迭代器所指向的元素,只是进行指针移动操作

  • list提供了一个迁移操作(transfer),将连续范围的元素迁移到某个特定位置之前,技术角度上讲是节点之间的指针移动
  • transfer迁移操作 是 其余操作(splice 、 sort 、 merge)的基础
  • transfer的源代码 

  • transfer接收的[first , last)区间可以在同一个list中
  • transfer不是公开的接口,list提供的是所谓的接合操作(splice) ,将某联系范围的元素从一个list移动到另一个(或者同一个)list的某个定点 
    //将[first , last) 内的所有元素 移动到 position之前void transfer(iterator position,iterator first,iterator last){if (last != position){(*(link_type((*last.node).prev))).next = position.node; //1(*(link_type((*first.node).prev))).next = last.node;    //2(*(link_type((*position.node).prev))).next = first.node;//3link_type tmp = link_type ((*position.node).prev);      //4(*position.node).prev = (*last.node).prev;              //5(*last.node).prev = (*first.node).prev;                 //6(*first.node).prev = tmp;                               //7}}

  • 本质上是节点之间的指针移动,上述splice、reverse、sort函数本身依靠的是transfer函数

  •  完整代码  不一定对
#include <iostream>
#include <list>template<class T,class Alloc>
class simple_alloc{
public:static T* allocate(std::size_t n){return 0==n?0:(T*)Alloc::allocate(n * sizeof(T));}static T* allocate(void){return (T*)Alloc::allocate(sizeof (T));}static void deallocate(T* p,size_t n){if (n!=0){Alloc::deallocate(p,n * sizeof(T));}}static void deallocate(T* p){Alloc::deallocate(p,sizeof(T));}
};namespace Chy{template <class T>inline T* _allocate(ptrdiff_t size,T*){std::set_new_handler(0);T* tmp = (T*)(::operator new((std::size_t)(size * sizeof (T))));if (tmp == 0){std::cerr << "out of memory" << std::endl;exit(1);}return tmp;}template<class T>inline void _deallocate(T* buffer){::operator delete (buffer);}template<class T1,class T2>inline void _construct(T1 *p,const T2& value){new(p) T1 (value);  //没看懂}template <class T>inline void _destroy(T* ptr){ptr->~T();}template <class T>class allocator{public:typedef T           value_type;typedef T*          pointer;typedef const T*    const_pointer;typedef T&          reference;typedef const T&    const_reference;typedef std::size_t size_type;typedef ptrdiff_t   difference_type;template<class U>struct rebind{typedef allocator<U>other;};pointer allocate(size_type n,const void * hint = 0){return _allocate((difference_type)n,(pointer)0);}void deallocate(pointer p,size_type n){_deallocate(p);}void construct(pointer p,const T& value){_construct(p,value);}void destroy(pointer p){_destroy(p);}pointer address(reference x){return (pointer)&x;}const_pointer const_address(const_reference x){return (const_pointer)&x;}size_type max_size()const{return size_type(UINT_MAX/sizeof (T));}};
}//如果是copy construction 等同于assignment而且destructor 是 trivial以下就会有效
//如果是POD型别 执行的流程就会跳转到以下函数,这个是通过function template的参数推导机制得到的
template<class ForwardIterator,class Size,class T>
inline ForwardIterator __uninitizlized_fill_n_aux(ForwardIterator first,Size n,const T&x){return fill_n(first,n,x); //交给高阶函数执行
}struct __true_type{};
struct __false_type{};template<class T>
struct __type_traits {typedef __true_type this_dummy_member_must_be_first;typedef __false_type has_trivial_default_constructor;typedef __false_type has_trivial_copy_constructor;typedef __false_type has_trivial_assignment_constructor;typedef __false_type has_trivial_destructor;typedef __false_type is_POD_type;
};//函数的逻辑是
//首先萃取出 迭代器first的value type,然后判断这个型别是否是POD类型
template<class ForwardIterator,class Size,class T,class T1>
inline ForwardIterator __uninitizlized_fill_n(ForwardIterator first,Size n,const T&x,T1*){//以下使用的是__type_traits<T1>::is_POD_type is _PODtypedef typename __type_traits<T1>::is_POD_type is_POD;return __uninitizlized_fill_n_aux(first,n,x,is_POD());
}template<class ForwardIterator,class Size,class T>
ForwardIterator uninitialized_fill_n(ForwardIterator first,Size n,const T&x){return __uninitizlized_fill_n(first,n,x,value_type(first));//使用value_type()判断first的value type
}//list的节点结构设计
template <class T>
struct __list_node{typedef void* void_pointer;void_pointer prev;   //指针的类型是void*,其实可以将其设定为 __list_node<T>void_pointer next;T data;
};//list的迭代器设计
template <class T,class Ref,class Ptr>
struct __list_iterator{typedef __list_iterator<T,T&,T*>    iterator;typedef __list_iterator<T,Ref,Ptr>  self;typedef std::bidirectional_iterator_tag iterator_category;typedef T value_type;typedef Ptr pointer;typedef Ref reference;typedef __list_node<T>* link_type;typedef std::size_t size_type;typedef ptrdiff_t difference_type;link_type node;//迭代器内部需要一个普通的指针,指向list节点//constructor__list_iterator(){}__list_iterator(link_type x):node(x){}__list_iterator(const iterator& x):node(x.node){}bool operator==(const self& x) const{return (node == x.node);}bool operator!=(const self& x) const{return (node != x.node);}//以下对迭代器取值 取得的是节点的数据值reference operator*() const {return (*node).data;}//以下是对迭代器的成员进行存取 (member access) 运算子的标准做法pointer operator->() const {return &(operator*());}//对迭代器进行加一 前进一个节点self& operator++(){node = (link_type)((*node).next);}self operator++(int){self tmp = *this;++*this;return tmp;}//对迭代器进行减一 后退一个节点self& operator--(){node = (link_type)((*node).prev);}self operator--(int){self tmp = *this;--*this;return tmp;}};//list 环状双向链表设计如下
template <class T,class Alloc> //缺省使用alloc作为配置器
class list{protected:typedef typename __list_iterator<T,T&,T*>::iterator iterator;typedef typename __list_iterator<T,T&,T*>::value_type value_type;typedef typename __list_iterator<T,T&,T*>::reference reference;typedef typename __list_iterator<T,T&,T*>::size_type size_type;typedef __list_node<T> list_node;//专属空间配置器 每次配置一个节点的大小
public:typedef list_node* link_type;typedef simple_alloc<list_node,Alloc>list_node_allocator;//list_node_allocator(n) 表示分配n个节点空间,以下四个函数分别用来配置、释放、构造、销毁一个节点
protected://配置一个节点并返回link_type get_node(){return list_node_allocator::allocate();}//释放一个节点link_type put_node(){return list_node_allocator::deallocate();}//产生(配置并构造)一个节点 带有元素数值link_type create_node(const T& x){link_type p = get_node();Chy::allocator<T>::construct(p->data,x); //全局函数 构造/析构基本工具return p;}//销毁 (析构并释放) 一个节点void destroy_node(link_type p){Chy::allocator<T>::destroy(&p->data);  //全局函数 构造/析构基本工具}public://让指针node刻意指向尾端的一个空白节点,node节点便会符合STL对于前开后闭区间的要求,成为list迭代器iterator begin(){return (link_type)(*node->next);}iterator end(){return node;}bool empty()const{return node->next == node;}size_type size()const{size_type result = 0;std::distance(begin(),end(),result);return result;}//取头部节点的内容(元素数值)reference front(){return *begin();}//取尾节点的内容(元素数值)reference back(){return *(--end());}//插入元素 供push_back()函数调用//insert函数 需要配置并构造一个节点,然后在尾端进行指针操作,将新的节点插入进去//函数的目的是为了在迭代器指定的位置插入一个节点,内容为xiterator insert(iterator position,const T&x){ //产生一个节点,默认初始化元素数值为xlink_type tmp = create_node(x);//调整双指针 将tmp插入进去tmp->next = position.node;tmp->prev = position.node->prev;(link_type(position.node->prev))->next = tmp;position.node->prev = tmp;return tmp;}//插入一个节点 作为头部节点void push_front(const T& x){insert(begin(),x);}//插入一个节点 作为尾节点void push_back(const T& x){insert(end(),x);}//移除迭代器position指向的节点iterator erase(iterator position){link_type next_node = link_type (position.node->next);link_type prev_node = link_type (position.node->prev);prev_node->next = next_node;next_node->prev = prev_node;destroy_node(position.node);return iterator (next_node);}//移除头部节点void pop_front(){erase(begin());}//移除尾部节点void pop_back(){iterator tmp = end();erase(--tmp);}//将[first , last) 内的所有元素 移动到 position之前void transfer(iterator position,iterator first,iterator last){if (last != position){(*(link_type((*last.node).prev))).next = position.node; //1(*(link_type((*first.node).prev))).next = last.node;    //2(*(link_type((*position.node).prev))).next = first.node;//3link_type tmp = link_type ((*position.node).prev);      //4(*position.node).prev = (*last.node).prev;              //5(*last.node).prev = (*first.node).prev;                 //6(*first.node).prev = tmp;                               //7}}public://构造函数//产生一个空的链表list(){empty_initialize();} //产生一个空的链表void clear();void remove(const T& value);void unique();protected:link_type node; //只需要一个指针,便可以循环遍历整个环状的双向链表//空初始化void empty_initialize(){node = get_node();  //配置一个节点空间,令node指向它node->next = node;  //令node头尾指向自己  不设置元素值node->prev = node;}public://将x结合于position所指定位置之前 x必须不同于*thisvoid splice(__list_iterator<T, T &, T *>, list &x);//将i指向的元素结合于position所指定的位置之前。position和i可以指向同一个listvoid splice(iterator position,list& ,iterator i){iterator j = i;++j;if (position == i || position == j){return;}transfer(position,i,j);}//将[first,last)内的元素接合于position指定的位置之前//position 和 [first,last)内可能指向的是同一个list//但是position 不能位于 [first,last)内部void splice(iterator position,list &,iterator first,iterator last){if (first != last){transfer(position,first,last);}}//merage() 将x合并到*this身上,但是两个lists的内容都必须要先经过递增排序void meage(list& x){iterator first1 = begin();iterator last1  = end();iterator first2 = x.begin();iterator last2 = x.end();//两个list实现需要经过排序while (first1 != last1 && first2 != last2){if (*first2 < *first1){iterator next = first2;transfer(first1,first2,++next);first2 = next;} else{++first1;}if (first2 != last2){transfer(last1,first2,last2);}}}//reverse() 将this的内容 逆向重置void reverse(){//以下判断,如果是空的链表,或者仅仅只有一个元素,就不进行任何的操作//使用size() == 0 || size() == 1 判断,速度较慢if (node->next == node ||link_type(node->next)->next == node)return;iterator first = begin();++first;while (first != end()){iterator old = first;++first;transfer(begin(),old,first);}}//list不能使用STL算法的sort() 因为STL算法只接受randomAccessIterator//本函数使用快速排序void sort(){//以下判断,如果是空的链表,或者仅仅只有一个元素,就不进行任何的操作//使用size() == 0 || size() == 1 判断,速度较慢if (node->next == node ||link_type(node->next)->next == node)return;//使用一些新的lists 作为中介数据存储区list carry;list counter[64];int fill = 0;while (!empty()){carry.splice(carry.begin(),*this,begin());int i = 0;while (i < fill && !counter[i].empty()){counter[i].merage(carry);carry.swap(counter[i++]);}carry.swap(counter[i]);if (i == fill){++fill;}}for (int i = 1; i < fill; ++i) {counter[i].merage(counter[i-1]);}std::swap(counter[fill-1]);}
};//清除所有的节点(整个链表)
template <class T,class Alloc>
void list<T,Alloc>::clear() {link_type cur = (link_type)node->next; //begin()while (cur != node){   //遍历每一个节点link_type tmp = cur;cur = (link_type)cur->next;destroy_node(tmp); //销毁、析构释放一个节点}//恢复node的原始状态node->next = node;node->prev = node;
}//清除数值为value的所有元素
template<class T,class Alloc>
void list<T,Alloc>::remove(const T &value) {typedef typename __list_iterator<T,T&,T*>::iterator iterator;iterator first = __list_iterator<T,T&,T*>::begin();iterator last = __list_iterator<T,T&,T*>::end();while (first != last){iterator next = first;++next;if (*first == value){__list_iterator<T,T&,T*>::erase(value);first = next;}}
}//移除数值相同的连续元素,注意:只有"连续并且相同的元素",才会被删除只剩一个
template <class T,class Alloc>
void list<T,Alloc>::unique() {typedef typename __list_iterator<T,T&,T*>::iterator iterator;iterator first = __list_iterator<T,T&,T*>::begin();iterator last = __list_iterator<T,T&,T*>::end();if (first == last){return; //空的链表  什么都不做}iterator next = first;while(++next != last){       //遍历每一个节点if (*first == *next){    //如果这个区段中存在相同的元素__list_iterator<T,T&,T*>::erase(next); //移除之} else{first = next;        //调整指针}next = first;            //修正区段范围}
}template <class T,class Alloc>
void list<T,Alloc>::splice(__list_iterator<T, T &, T *>position, list<T, Alloc> &x) {if (!x.empty()){transfer(position,x.begin(),x.end());}
}
  • 涉及到transfer的相关函数的代码 理解不是很透彻 垃圾

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/446278.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

vsftp不允许切换到其它目录_IntelliJ IDEA如何对project的目录进行筛选显示?

如果你的项目很庞大&#xff0c;同一个功能用到的各种文件散落在多个文件夹&#xff0c;开发时切换不便&#xff0c;可以利用scope功能&#xff0c;只显示该功能用到的文件&#xff0c;让project列表十分清爽&#xff0c;提高开发效率。本文使用的IDEA版本为2020.1。1、打开sco…

密码学专题 对称加密算法

一般来说&#xff0c;使用OpenSSL对称加密算法有两种方式&#xff0c;一种是使用API函数的方式&#xff0c;一种是使用OpenSSL提供的对称加密算法指令方式。本书将介绍对称加密算法的指令方式OpenSSL的对称加密算法指令主要用来对数据进行加密和解密处理&#xff0c;输入输出的…

网络防火墙单向和双向_单向晶闸管与双向晶闸管之间的不同之处

晶闸管是回一个可以控导点开关&#xff0c;能以弱电去控制强电的各种电路。晶闸管常用于整流&#xff0c;调压&#xff0c;交直流变化&#xff0c;开关&#xff0c;调光等控制电路中。具有提交小&#xff0c;重量轻&#xff0c;耐压高&#xff0c;容量大&#xff0c;效率高&…

python版本切换_怎么切换python版本

展开全部 &#xff08;1&#xff09;分别安2113装 python-2.7.12.amd64.msi python-3.5.2-amd64.exe &#xff08;python官网下载的&#xff09; 顺序无所谓&#xff08;为5261了看着4102方便&#xff0c;我把安装路径修改统一了1653&#xff09; &#xff08;2&#xff09;配置…

react.lazy 路由懒加载_Vue面试题: 如何实现路由懒加载?

非懒加载import List from /components/list.vue const router new VueRouter({routes: [{ path: /list, component: List }] })方案一(常用)const List () > import(/components/list.vue) const router new VueRouter({routes: [{ path: /list, component: List }] })方…

STL源码剖析 deque双端队列 概述

vector是单向开口的连续线性空间&#xff0c;deque是一种双向开口的连续线性空间。deque可以在头尾两端分别进行元素的插入和删除操作vector和deque的差异 1&#xff0c;deque允许常数时间内对于头端元素进行插入和删除操作2&#xff0c;deque没有所谓容量(capacity)的概念&…

STL源码剖析 stack 栈 概述->(使用deque双端队列 / list链表)作为stack的底层容器

Stack是一种先进后出的数据结构&#xff0c;他只有一个出口stack允许 新增元素、移除元素、取得最顶端的元素&#xff0c;但是无法获得stack的内部数据&#xff0c;因此satck没有遍历行为Stack定义的完整列表 (双端队列作为Stack的底层容器) 将deque作为Stack的底部结构&#…

python怎么实现图像去噪_基于深度卷积神经网络和跳跃连接的图像去噪和超分辨...

Image Restoration Using Very Deep Convolutional Encoder-Decoder Networks with Symmetric Skip Connections作者&#xff1a;Xiao-Jiao Mao、Chunhua Shen等本文提出了一个深度的全卷积编码-解码框架来解决去噪和超分辨之类的图像修复问题。网络由多层的卷积和反卷积组成&a…

STL源码剖析 queue队列概述

queue是一种先进先出的数据结构&#xff0c;他有两个出口允许新增元素&#xff08;从最底端 加入元素&#xff09;、移除元素&#xff08;从最顶端删除元素&#xff09;&#xff0c;除了对于顶端和底端元素进行操作之外&#xff0c;没有办法可以获取queue的其他元素即queue没有…

python为什么运行不了_python为什么会环境变量设置不成功

学习python编程&#xff0c;首先要配置好环境变量。本文主要讲解python的环境变量配置&#xff0c;在不同版本下如何安装 Windows 打开Python官方下载网站 x86:表示是32位电脑 x86-64:表示是64位电脑 目前Python版本分为2.x版本和3.x版本。推荐大家使用3.x版本。 设置环境变量&…

STL 源码剖析 heap堆

heap不属于STL容器的组件&#xff0c;属于幕后角色&#xff0c;是priority_queue的助手priority_queue 允许用户以任何次序将任何元素推入容器内&#xff0c;但是取出的时候需要从优先级最高(也就是数值最高)的元素开始取&#xff0c;这种思想是基于heap的函数实现如果使用list…

java 打印星号

代码1 package lesson.l2_for; //6列4行 //****** //****** //****** //****** public class ForDemo8 {public static void main(String[] args) {for (int i1;i<4;i){for (int j 1; j <6 ; j) {System.out.print("*");}System.out.println();}} }代码2 pa…

python从小白到大牛百度云盘_Java从小白到大牛 (关东升著) 中文pdf+mobi版[36MB]

《Java从小白到大牛》是一本Java语言学习立体教程&#xff0c;读者群是零基础小白&#xff0c;通过本书的学习能够成为Java大牛。主要内容包括&#xff1a;Java语法基础、Java编码规范、数据类型、运算符、控制语句、数组、字符串、面向对象基础、继承与多态、抽象类与接口、枚…

java打印九九乘法表

代码1 package lesson.l5_loop; //九九乘法表 //1*11 //2*12 2*24 //3*13 3*26 3*39 //4*14 4*28 4*312 4*416 //5*15 5*210 5*315 5*420 5*525 //6*16 6*212 6*318 6*424 6*530 6*636 //7*17 7*214 7*321 7*428 7*535 7*642 7*749 //8*18 8*216 8*324 8*432 8*540 8*648 8*75…

STL源码剖析 priority_queue

priority_queue是一个拥有权重概念的queue&#xff0c;允许底部加入新的元素&#xff0c;头部删除旧的元素&#xff0c;以及审视元素数值的操作priority_queue带有权重的概念&#xff0c;即元素按照权重进行排列&#xff0c;而不是按照插入队列的顺序进行排序。要求权值高者在前…

python数字1 3怎么表示_Python入门篇之数字

数字类型 数字提供了标量贮存和直接访问。它是不可更改类型&#xff0c;也就是说变更数字的值会生成新的对象。当然&#xff0c;这个过程无论对程序员还是对用户都是透明的&#xff0c;并不会影响软件的开发方式。 Python 支持多种数字类型&#xff1a;整型、长整型、布尔型、双…

STL源码剖析 slist单向链表概述

概述 SGI STL的list是一个双向链表&#xff0c;单向链表是slist&#xff0c;其不在标准规格之内单向和双向链表的区别在于&#xff0c;单向链表的迭代器是单向的 Forward Iterator&#xff0c;双向链表的迭代器属于双向的Bidirectional Iterator。因此很多功能都被受限但是单向…

output怎么用_用树莓派实现室内温度监控

树莓派加上温度传感器实现室内温度监控。可用于家庭&#xff0c;轿车&#xff0c;工业&#xff0c;农业 等许多方面。可做温度预警&#xff0c;自动降温等操作。各位小伙伴可自行脑补发挥。1.硬件准备a.树莓派&#xff08;Raspberry Pi&#xff09;一个b.DS18B20温度传感器一个…

STL源码剖析 关联式容器

STL关联式容器以set(集合) 和 map(映射表)两大类&#xff0c;以及对应的衍生体构成,比如mulyiset(多键集合) multimap(多键映射表) ,容器的底层均基于红黑树RB-Tree也是一个独立的容器&#xff0c;但是不对外开放此外还提供了标准之外的关联式容器 hash table散列表&#xff0c…

STL源码剖析 关联式容器 红黑树

概念 红黑树不仅仅是一个二叉树&#xff0c;必须满足如下条件1&#xff0c;每个节点不是红色就是黑色 (深色底纹为黑色&#xff0c;浅色底纹为红色)2&#xff0c;根节点是黑色的3&#xff0c;如果节点为红&#xff0c;其子节点必须为黑色的4&#xff0c;任一节点至NULL(树的尾…