C++学习记录——십이 vector
文章目录
- 1、vector介绍和使用
- 2、vector模拟实现
- insert和erase和迭代器失效
- 补齐其他函数
- 深浅拷贝
- 难点思考
1、vector介绍和使用
vector可以管理任意类型的数组,是一个表示可变大小数组的序列容器。
通过vector文档来看它的使用。
#include <iostream>
#include <vector>
using namespace std;void test_vector1()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);
}int main()
{test_vector1();return 0;
}
要使用vector需要先引头文件。现在插入一些元素后,要遍历v,可以用[],范围for,迭代器。
//[]for (size_t i = 0; i < v.size(); ++i){cout << v[i] << " ";}cout << endl;//迭代器vector<int>::iterator it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;//范围forfor (auto e : v){cout << e << " ";}cout << endl;
创建一个数组并遍历可以这样写
void test_vector2()
{vector<int> v1(10, 1);for (auto e : v1){cout << e << " ";}cout << endl;vector<int> v2(v1.begin(), v1.end());//用迭代器范围来遍历数组for (auto e : v2){cout << e << " ";}cout << endl;
}
刚才提到vector可以传任何类型,string类也可以。
string s1("hello world");vector<int> v3(s1.begin(), s1.end());for (auto e : v3){cout << e << " ";}cout << endl;
不过打印的是ANSCII码值罢了。
写一下反向迭代器
//vector<int>::reverse_iterator rit = v.rbegin();auto rit = v.rbegin();//也可以使用autowhile (rit != v.rend()){cout << *rit << " ";++rit;}cout << endl;
对于vector,初始化变得很简单
void test_vector4()
{vector<int> v;v.resize(10, 0);//初始化10个元素为0
}
vector的insert和erase和string不一样,它要配合迭代器。且vector的查找元素是用std的find函数。
vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator pos = find(v.begin(), v.end(), 2);if (pos != v.end()){v.insert(pos, 20);}for (auto e : v){cout << e << " ";}cout << endl;
而想删除不能直接erase
pos = find(v.begin(), v.end(), 2);if (pos != v.end()){v.erase(pos);}for (auto e : v){cout << e << " ";}cout << endl;
因为这时候迭代器失效了。头删就可以直接v.erase(v.begin())。
2、vector模拟实现
基本功能。扩容函数需要注意一下,防止程序崩掉,三个变量的赋值要考虑具体的结果。
vector.h
#pragma once
#include <iostream>
using namespace std;
#include<assert.h>namespace zyd
{template<class T>class vector{public:typedef T* iterator;vector():_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){}iterator begin(){return _start;}iterator end(){return _finish;}void reserve(size_t n){if (n > capacity()){size_t sz = size();T* tmp = new T[n];if (_start){memcpy(tmp, _start, sizeof(T) * size());delete[] _start;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}}void push_back(const T& x){if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}*_finish = x;++_finish;}void pop_back(){assert(!empty());--_finish;}size_t capacity() const{return _end_of_storage - _start;}size_t size() const{return _finish - _start;}bool empty(){return _start == _finish;}T& operator[](size_t pos){assert(pos < size());return _start[pos];}private:iterator _start;iterator _finish;iterator _end_of_storage;};void test_vector1(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);for (size_t i = 0; i < v1.size(); ++i){cout << v1[i] << " ";}cout << endl;v1.pop_back();v1.pop_back();v1.pop_back();v1.pop_back();vector<int>::iterator it = v1.begin();while (it != v1.end()){cout << *it << " ";}cout << endl;for (auto e : v1){cout << e << " ";}cout << endl;}
}
针对const对象的访问,我们写一个func函数放在和test函数同样的位置。
void func(const vector<int>& v){for (size_t i = 0; i < v.size(); ++i){cout << v[i] << " ";}cout << endl;vector<int>::const_iterator it = v.begin();while (it != v.end()){cout << *it << " ";++it;}cout << endl;}}
然后再写上所调用成员函数的const函数,以及const版本的迭代器。
typedef T* iterator;typedef const T* const_iterator;
写一下resize()。如果传的参数n小于size,那就是删数据,如果大于,那么要扩容,还有新的空间要初始化,库里用了缺省参数,T val = T()。T()其实是一个匿名的默认构造,对自定义类型有用,对内置类型也适用,C++做了相关的函数,int a = int();,就会初始化a为0。但是指针不能这样写。
template<class T>void f(){T i = T();cout << i << endl;}void test_vector2(){/*int a = int();int b = int(1);cout << a << endl;cout << b << endl;*/f<int>();f<int*>();f<double>();}
引入模板后,什么内置类型就可以了。
回到resize函数。
void resize(size_t n, T val = T()){if (n < size()){//删除数据_finish = _start + n;}else{if (n > capacity())reserve(n);while (_finish != _start + n){*_finish = val;++_finish;}}}
void test_vector3(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);cout << v1.size() << endl;cout << v1.capacity() << endl;v1.resize(10);cout << v1.size() << endl;cout << v1.capacity() << endl;func(v1);}
扩容后新空间就是0
insert和erase和迭代器失效
void insert(iterator pos, const T& val){assert(pos >= _start && pos <= _finish);if (_finish == _end_of_storage){reserve(capacity() == 0 ? 4 : capacity() * 2);}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;}
vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);/*cout << v1.size() << endl;cout << v1.capacity() << endl;v1.resize(10);cout << v1.size() << endl;cout << v1.capacity() << endl;func(v1);*/v1.insert(v1.begin(), 0);func(v1);auto pos = find(v1.begin(), v1.end(), 3);if (pos != v1.begin()){v1.insert(pos, 30);}func(v1);
一个头插,一个第3个位置插入,结果如下
如果是5个,也就是进行了一次扩容后,就没问题了。有的编译器这里会崩掉。
在insert函数里,我们插入了4个数据,那么就会扩容一次,开新空间,旧空间释放,扩容之后_start _finish _end_of_storage都会变,但是pos还是指向原先的空间,pos就变成了野指针,这时候就变成了迭代器失效。为了解决这个问题,我们需要找到pos的新的相对位置。
void insert(iterator pos, const T& val){assert(pos >= _start && pos <= _finish);if (_finish == _end_of_storage){size_t len = pos - _start;reserve(capacity() == 0 ? 4 : capacity() * 2);pos = _start + len;}iterator end = _finish - 1;while (end >= pos){*(end + 1) = *end;--end;}*pos = val;++_finish;}
如果是插入5个,那么在找pos之前就已经扩容了,pos是按照新空间去找位置,所以就没问题。
都插入完成后,对pos位置++
auto pos = find(v1.begin(), v1.end(), 3);if (pos != v1.begin()){v1.insert(pos, 30);}func(v1);(*pos)++;func(v1);
会发现什么都没发生。实际上这里越界了。这是因为虽然函数里面改正了pos,但是没传出去,所以外面还是以前的pos。如果函数里面pos没有改,那就没问题。insert目前是传值传参,但不能把pos改成引用传参,会报错。这是因为begin和end函数是传值,不能传给引用,所以insert返回pos就好。也可以不写这个返回,不在外面用pos就行。
erase函数
void erase(iterator pos){assert(pos >= _start && pos < _finish);iterator start = pos + 1;while (start != _finish){*(start - 1) = *start;++start;}--_finish;}
void test_vector4(){vector<int> v1;v1.push_back(1);v1.push_back(2);v1.push_back(3);v1.push_back(4);for (auto e : v1){cout << e << " ";}cout << endl;auto pos = find(v1.begin(), v1.end(), 3);if (pos != v1.begin()){v1.erase(pos);}for (auto e : v1){cout << e << " ";}cout << endl;}
刚才insert之后pos失效了,erase这里也会报错,pos会失效,最好不要访问,不容易控制,因为行为结果未定义,不同平台不同结果。
erase也可以认为是迭代器失效。如果pos是最后一个数据位置,那么删除后,finish会往前一步,但依然在最后一个元素后面,这时候pos和finish同一位置,实际上这时候pos已经失效了。
改一下erase函数
iterator erase(iterator pos){assert(pos >= _start && pos < _finish);iterator start = pos + 1;while (start != _finish){*(start - 1) = *start;++start;}--_finish;return pos;}
测试代码
void test_vector5(){vector<int> v1;v1.push_back(10);v1.push_back(2);v1.push_back(3);v1.push_back(4);v1.push_back(5);v1.push_back(50);for (auto e : v1){cout << e << " ";}cout << endl;vector<int>::iterator it = v1.begin();while (it != v1.end()){if (*it % 2 == 0){it = v1.erase(it);}else{++it;}}cout << endl;for (auto e : v1){cout << e << " ";}cout << endl;}
补齐其他函数
~vector(){delete[] _start;_start = _finish = _end_of_storage = nullptr;}
vector还有别的构造。vector接口参数里的缺省参数通常不用0,而是const T& val = T(),防止类型冲突。但这里是否需要考虑匿名对象的生命周期只在这一行?
先测一下这个问题
class A
{
public:A(){cout << "A()" << endl;}~A(){cout << "~A()" << endl;}
};A a1;A();A a2;return 0;
可以看到确实是这样,a1和a2是在return0那里才都销毁,而A()直接就销毁。但入如果const A& xx = A(),就会使用上这个对象,一直到引用对象xx生命周期结束时才析构。
但不加const就不行,因为像匿名对象这样的临时对象都是有常性的。
继续写初始化构造函数。
vector(size_t n, const T& val = T()):_start(nullptr), _finish(nullptr), _end_of_storage(nullptr){reserve(n);for (size_t i = 0; i < n; ++i){push_back(val);}}
测试代码
zyd::vector<int> v1(10, 5);for (auto e : v1){cout << e << " ";}cout << endl;
vector也有排序
v1.insert(v1.begin(), 10);sort(v1.begin(), v1.end());for (auto e : v1){cout << e << " ";}cout << endl;
除此之外,数组也可以。默认为升序。如果想降序,需要用到greater这个模板,它可以用任何类型,以及头文件#include < functional >。
greater<int> g;sort(v1.begin(), v1.end(), g);
也可以
sort(v1.begin(), v1.end(), greater<int>());
深浅拷贝
vector(const vector<T>& v){reserve(v.capacity());memcpy(_start, v._start, sizeof(T) * v.size());_finish = _start + v.size();}
但是这个程序应对string类对象的拷贝就崩了。
vector<std::string> v3(10, "1111111");for (auto e : v3){cout << e << " ";}cout << endl;vector<std::string> v4(v3);for (auto e : v4){cout << e << " ";}cout << endl;
用vector<vector< int >>也出错。这是因为虽然我们自己写了深拷贝,但是开空间后,memcpy在一个个拷贝时也相当于浅拷贝,v4和v3的_start都指向了同一块空间,所以这里是memcpy浅拷贝了,函数析构时会崩掉。
这里的解决办法就是挨个赋值。自定义类型的赋值会开一样大的空间,然后填充内容。
同样地,扩容也是memcpy,调起调试可以看出memcpy的两个对象是同一个指针。所以这里也要改。
void reserve(size_t n){if (n > capacity()){size_t sz = size();T* tmp = new T[n];if (_start){//memcpy(tmp, _start, sizeof(T) * size());for (size_t i = 0; i < sz; ++i){tmp[i] = _start[i];}delete[] _start;}_start = tmp;_finish = _start + sz;_end_of_storage = _start + n;}}
这样其他类型的也都可以了。
难点思考
void test_vector8(){class Solution{public:vector<vector<int>> generate(int numRows){vector<vector<int>> vv;vv.resize(numRows, vector<int>());for (size_t i = 0; i < vv.size(); ++i){vv[i].resize(i + 1, 0);vv[i][0] = vv[i][vv[i].size() - 1] = 1;}for (size_t i = 0; i < vv.size(); ++i){for (size_t j = 0; j < vv[i].size(); ++j){if (vv[i][j] == 0){vv[i][j] = vv[i - 1][j] + vv[i - 1][j - 1];}}}return vv;}};vector<vector<int>> ret = Solution().generate(5);for (size_t i = 0; i < ret.size(); ++i){for (size_t j = 0; j < ret[i].size(); ++j){cout << ret[i][j] << " ";}cout << endl;}cout << endl;}
}
我们的拷贝构造函数是这样
vector(const vector<T>& v){reserve(v.capacity());//memcpy(_start, v._start, sizeof(T) * v.size());for (size_t i = 0; i < v.size(); ++i){_start[i] = v._start[i];}_finish = _start + v.size();}
程序崩了,是因为浅拷贝问题,赋值浅拷贝。vv是深拷贝,而ret是浅拷贝。
赋值=没有重载函数
void swap(vector<T>& v){std::swap(_start, v._start);std::swap(_finish, v._finish);std::swap(_end_of_storage, v._end_of_storage);}vector<T>& operator=(vector<T> v){swap(v);return *this;}
结束。
相关文章:
C++学习记录——십이 vector
文章目录1、vector介绍和使用2、vector模拟实现insert和erase和迭代器失效补齐其他函数深浅拷贝难点思考1、vector介绍和使用 vector可以管理任意类型的数组,是一个表示可变大小数组的序列容器。 通过vector文档来看它的使用。 #include <iostream> #inclu…...
Lombok常见用法总结
目录一、下载和安装二、常见注释(一)Data(二)Getter和Setter(三)NonNull和NotNull(不常用)(四)ToString(不常用)(五&#…...
【Ajax】异步通信
一.概述 概念:AJAX(Asynchronous JavaScript And XML):异步的 JavaScript 和 XML 作用: 与服务器进行数据交换:通过AJAX可以给服务器发送请求,并获取服务器响应的数据 使用了AJAX和服务器进行通信,就可以使…...
近红外吸收荧光染料IR-808,IR-808 NH2,IR-808 amine,发射808nm 性质分享
中文名称:IR-808 氨基英文名称:IR-808 NH2,IR-808 amine,IR-808-NH2规格标准:10mg,25mg,50mgCAS:N/A产品描述:IR-808,发射808nm,酯溶性染料修饰氨…...
一图来看你需要拥有那些知识储备
技术实践 数据 关系型数据 MySQLSQLServerOraclePostgrSQLDB2 大数据存储 RedisMemcacheMongoDBHBaseHive 大数据处理 Hadoop 数据报表看板 DataGearGrafanaKibanaMetaBase 消息对列 Rabbit MQRock MQActive MQKafka 大数据搜索 SolrElasticSearchLucenHive 服务提…...
复位和时钟控制(RCC)
目录 复位 系统复位 电源复位 备份区复位 时钟控制 什么是时钟? 时钟来源 二级时钟源: 如何使用CubeMX配置时钟 复位 系统复位 当发生以下任一事件时,产生一个系统复位:1. NRST引脚上的低电平(外部复位) 2. 窗口看门狗计数终止(WWD…...
OpenWrt 专栏介绍00
文章目录OpenWrt 专栏介绍00专栏章节介绍关于联系方式OpenWrt 专栏介绍00 专栏章节介绍 本专栏主要从开发者角度,一步步深入理解OpenWrt开发流程,本专栏包含以下章节,内如如下: 01.OperWrt 环境搭建02.OperWrt 包管理系统03.Op…...
udk开发-稀里糊涂
一、EDK2简介 1.EDK2工作流 二、EDK2 Packages 1.Packages介绍 EDK2 Packages是一个容器,其中包含一组模块及模块的相关定义。每个Package是一个EDK2单元。 整个Project的源代码可以被分割成不同的Pkg。这样的设计不仅可以降低耦合性,还有利于分…...
Java之内部类
目录 一.内部类 1.什么是内部类 2.内部类存在的原因 3. 内部类的分类 4.内部类的作用 二.成员内部类 1.基本概念 2.成员内部类的注意点 1.成员内部类可以用private方法进行修饰 2.成员内部类可以直接访问外部类的私有属性 3.外部类可以通过对象访问内部类的私有属性 …...
【MyBatis】篇二.MyBatis查询与特殊SQL
文章目录1、MyBatis获取参数值case1-单个字面量类型的参数case2-多个字面量类型的参数case3-map集合类型的参数case4-实体类类型的参数case5-使用Param注解命名参数总结2、MyBatis的各种查询功能case1-查询结果是一个实体类对象case2-查询结果是一个List集合case3-查询单个数据…...
CE认证机构和CE证书的分类
目前,CE认证已普遍被应用在很多行业的商品中,也是企业商品进入欧洲市场的必备安全合格认证。在船舶海工行业中,也同样普遍应用,很多时候,对于规范中没有明确认证要求的设备或材料,而船舶将来还会去欧洲水域…...
Lesson 8.2 CART 分类树的建模流程与 sklearn 评估器参数详解
文章目录一、CART 决策树的分类流程1. CART 树的基本生长过程1.1 规则评估指标选取与设置1.2 决策树备选规则创建方法1.3 挑选最佳分类规则划分数据集1.4 决策树的生长过程2. CART 树的剪枝二、CART 分类树的 Scikit-Learn 快速实现方法与评估器参数详解1. CART 分类树的 sklea…...
【Unity】程序集Assembly模块化开发
笔者按:使用Unity版本为2021.3LTS,与其他版本或有异同。请仅做参考 一、简述。 本文是笔者在学习使用Unity引擎的过程中,产学研的一个笔记。由笔者根据官方文档Unity User Manual 2021.3 (LTS)/脚本/Unity 架构/脚本编译/程序集定义相关部分结…...
马尔可夫决策过程
1. 马尔可夫决策过程 马尔可夫决策过程不过是引入"决策"的马氏过程. Pij(a)P{Xn1j∣X0,a0,X1,a1,...,Xni,an1}P{Xnn1j∣Xni,ana}\begin{split} P_{ij}(a) & P\{X_{n1} j|X_0, a_0, X_1, a_1, ..., X_n i, a_n 1\} \\ &P\{X_n{n1} j|X_n i, a_n a\} \e…...
win11下载配置CIC Flowmeter环境并提取流量特征
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录前言一、下载CIC Flowmeter二、安装java、maven、gradle和IDEA1.java 1.82.maven3.gradle4.IDEA三、CICFlowMeter-master使用四、流量特征1.含义2.获取前言 配了一整…...
JDK如何判断自己是什么公司的
0x00 前言 因为一些事情,遇到了这样一个问题,JDK如何判断自己是什么公司编译的。因为不同的公司编译出来,涉及到是否商用收费的问题。 平时自己使用的时候,是不会考虑到JDK的编译公司是哪一个,都是直接拿起来用&#…...
大数据技术之HBase(二)HBase原理简介
一、HBase定义1.1 HBase定义HBase 是一种分布式、可扩展、支持海量数据存储的 NoSQL 数据库非结构化数据存储的数据库,基于列的模式存储。利用Hadoop HDFS作为其文件存储系统,写入性能很强,读取性能较差。利用Hadoop MapReduce来处理HBase中的…...
垒骰子(爆搜/DP)
动态规划方格取数垒骰子方格取数 题目描述 设有 NNN \times NNN 的方格图 (N≤9)(N \le 9)(N≤9),我们将其中的某些方格中填入正整数,而其他的方格中则放入数字 000。如下图所示(见样例): A0 0 0 0 0 0 0 00 0 13 0 …...
Telink之标准SDK的介绍_1
前提:常见的项目架构:应用层----》驱动层----》硬件层 1、软件组织架构 顶层⽂件夹( 8 个): algorithm,application,boot,common,drivers,proj_lib,stack,v…...
JNI内两种方式从C/C++中传递一维、二维、三维数组数据至Java层详细梳理
目录 0 前言 1 准备工作介绍 2 一维数组 2.1 return形式 2.2 参数形式 3 二维数组 3.1 return形式 3.2 参数形式 4 三维数组 4.1 return形式 4.2 参数形式 5 测试代码 6 结果说明 0 前言 就如之前我写过的一篇文章【JNI内形参从C代码中获取返回值并返回到Java层使…...
快递计费系统--课后程序(Python程序开发案例教程-黑马程序员编著-第3章-课后作业)
实例5:快递计费系统 快递行业高速发展,我们邮寄物品变得方便快捷。某快递点提供华东地区、华南地区、华北地区的寄件服务,其中华东地区编号为01、华南地区编号为02、华北地区编号为03,该快递点寄件价目表具体如表1所示。 表1 寄…...
JS - 自定义一周的开始和结束,计算日期所在月的周数、所在月第几周、所在周的日期范围
自定义一周的开始和结束,计算日期所在月的周数、所在月第几周、所在周的日期范围一. 方法使用二. 实现案例一. 方法使用 根据月开始日期星期几、月结束日期星期几,计算始周、末周占月的天数(每周周期段:上周六 —— 本周五&#x…...
Linux :理解编译的四个阶段
目录一、了解编译二、认识编译的四个阶段(一)预处理(二)编译(三)汇编(四)链接1.静态链接2.动态链接三、分步编译(一)创建.c文件(二)预…...
197.Spark(四):Spark 案例实操,MVC方式代码编程
一、Spark 案例实操 1.数据准备 电商网站的用户行为数据,主要包含用户的 4 种行为:搜索,点击,下单,支付 样例类: 2. Top10 热门品类 先按照点击数排名,靠前的就排名高;如果点击数相同,再比较下单数;下单数再相同,就比较支付数。 我们有多种写法,越往后性能越…...
Vue 项目如何迁移小程序
最近我们看到有开发者在社群里提出新的疑惑「我手头已经有一个成熟的 HTML5 项目了,这种项目可以转为小程序在 FinClip 环境中运行吗?」。 经过工作人员的沟通了解,开发者其实是想将已有的 Vue 项目转为小程序,在集成了 FinClip …...
unit1-问候以及介绍
unit1-问候以及介绍 重点表达 1、问好 使用hello 和 hi 来打招呼。hello可以使用在正式和非正式的场合。hi是非正式的。但是hello 和 hi 都可以在一天的任何时段使用。 Hello. 你好。 Hi! 嗨! 介绍你的姓名 使用 I’m 和 My name is 告诉别人你的名字。 I’m Pau…...
杂记——19.git上传时出现the remote end hung up unexpectedly错误
git是大家常用的项目版本控制工具,熟练地使用git可以提高开发效率,但是有时在使用git推送代码时,会提示“the remote end hung up unexpectedly”的问题,那么git推送代码提示“the remote end hung up unexpectedly”怎么解决呢&a…...
python123平台题目
作业二 1. 2的n次方描述输入格式输出格式输入输出实例代码解析2. 输出最大值描述输入格式输出格式输入输出示例代码解析3. 字符串输出描述输入格式输出格式输入输出示例代码解析4. 字符串长度描述输入格式输出格式输入输出示例代码解析...
ROS学习笔记(六):TF坐标变换
ROS学习笔记(六):TF坐标变换TF的基本知识TF工具tf_monitortf_echostatic_transform_publisherview_frames创建TF广播器创建TF监听器TF的基本知识 TF是一个让用户随时间跟踪多个坐标系的功能包,它使用树形数据结构,根据…...
【python】为你绘制玫瑰一束,爱意永存
前言 嗨喽~大家好呀,这里是魔王呐 ❤ ~! 若是有真情,爱意如溪水, 若是有真爱,爱意如阳光, 若是两情相悦,又岂在朝朝暮暮, 女子淡淡的情愫,深深地想念, 浓浓的爱意&a…...
ps做游戏下载网站有哪些/百度搜索量统计
泛型介绍(C# 编程指南)泛型类和泛型方法同时具备可重用性、类型安全和效率,这是非泛型类和非泛型方法无法具备的。泛型通常用在集合和在集合上运行的方法中。.NET Framework 2.0 版类库提供一个新的命名空间 System.Collections.Generic&…...
商城网站建设net2006/网站seo软件
Spring Cloud教程(非常详细) SpringCloud入门教程(全集) Spring Cloud 学习笔记(1 / 3) 狂神说SpringCloud学习笔记 史上最简单的 SpringCloud 教程 | 终章 史上最简单的 SpringCloud 教程 | 第一篇&a…...
什么网站可以做高数/五年级下册数学优化设计答案
基于注解方式的Bean管理 AOP 写法一:匿名内部类 写法二: AOP操作(AspectJ注解) AOP操作(AspectJ配置文件) JdbcTemplate(概念和准备)...
苏州企业网站制作电话/东营网站建设哪家更好
2-3树真的是非常完美的平衡二叉树了,平衡二叉树(BST)的要点在于它的每条从根节点到叶子节点的路径都具有相同的长度,并且在数据结构中,对于查找和插入操作,最糟糕的情况下时间复杂度为O(log n)。与我在第四十五天讲的BST有什么不一…...
深圳专业制作网站的公司哪家好/网站运营课程
原文:Best Practices for Speeding Up Your Web Site 26 开发灵巧的事件处理程序 Develop Smart Event Handlers tag:javascript 如果有太多的事件处理逻辑部署在DOM树的不同元素上,它们的频繁执行会拖慢页面的响应速度。而使用事件委托是一…...
怎样做网站管理/比较好的网络推广平台
这篇文章主要介绍了ThinkPHP在新浪SAE平台的部署的实现方法,以实例的形式详细讲述了WBlog的完整部署过程,需要的朋友可以参考下本文实例讲述了ThinkPHP在新浪SAE平台的部署方法。分享给大家供大家参考。具体实现方法如下:ThinkPHP自从thinkphp3.0版本开始提供了SAE平…...