99偷拍视频精品区一区二,口述久久久久久久久久久久,国产精品夫妇激情啪发布,成人永久免费网站在线观看,国产精品高清免费在线,青青草在线观看视频观看,久久久久久国产一区,天天婷婷久久18禁,日韩动漫av在线播放直播

C++vector-創新互聯

目錄

目前成都創新互聯已為近千家的企業提供了網站建設、域名、網頁空間、網站改版維護、企業網站設計、華龍網站維護等服務,公司將堅持客戶導向、應用為本的策略,正道將秉承"和諧、參與、激情"的文化,與客戶和合作伙伴齊心協力一起成長,共同發展。

1.vector的介紹及使用 ?

1.1 vector的介紹

1.2 vector的使用

1.2.1 vector的定義

1.2.2 vector iterator 的使用

1.2.3 vector 空間增長問題

1.2.3 vector 增刪查改

1.2.4 vector 迭代器失效問題。(重點)

1.2.5 vector 在OJ中的使用

2.vector深度剖析及模擬實現

使用memcpy拷貝問題

動態二維數組理解

模擬實現vector:


1.vector的介紹及使用 ? 1.1 vector的介紹
1. vector 是表示可變大小數組的序列容器。 2. 就像數組一樣, vector 也采用的連續存儲空間來存儲元素。也就是意味著可以采用下標對 vector 的元素進行訪問,和數組一樣高效。但是又不像數組,它的大小是可以動態改變的,而且它的大小會被容器自動處理。 3. 本質講, vector 使用動態分配數組來存儲它的元素。當新元素插入時候,這個數組需要被重新分配大小為了增加存儲空間。其做法是,分配一個新的數組,然后將全部元素移到這個數組。就時間而言,這是一個相對代價高的任務,因為每當一個新的元素加入到容器的時候,vector 并不會每次都重新分配大小。 4. vector 分配空間策略: vector 會分配一些額外的空間以適應可能的增長,因為存儲空間比實際需要的存儲空間更大。不同的庫采用不同的策略權衡空間的使用和重新分配。但是無論如何,重新分配都應該是對數增長的間隔大小,以至于在末尾插入一個元素的時候是在常數時間的復雜度完成的。 5. 因此, vector 占用了更多的存儲空間,為了獲得管理存儲空間的能力,并且以一種有效的方式動態增長。 6. 與其它動態序列容器相比( deque, list and forward_list ), vector 在訪問元素的時候更加高效,在末尾添加和刪除元素相對高效。對于其它不在末尾的刪除和插入操作,效率更低。比起list 和 forward_list統一的迭代器和引用更好
1.2 vector的使用 1.2.1 vector的定義

以上就是vector的構造函數,重點關注1和3

1.2.2 vector iterator 的使用

我們可以看到這里的iterator行為上就像指針一樣,但又不一定是指針?,而對于vector這里來說,這里的iterator就是一個原生指針,后面會講到迭代器失效的問題。

1.2.3 vector 空間增長問題

這里的resize和reserve和之前的string的含義一樣,這里就看看函數的使用方式即可:

capacity 的代碼在 vs 和 g++ 下分別運行會發現, vs下capacity是按1.5倍增長的,g++是按2倍增長的。 這個問題經常會考察,不要固化的認為, vector 增容都是 2 倍,具體增長多少是根據具體的需求定義的。 vs是PJ版本STL,g++是SGI版本STL 。( 也就是不同編譯器的實現方式不同,所以可能會導致有不同的結果) reserve 只負責開辟空間,如果確定知道需要用多少空間, reserve 可以緩解 vector 增容的代價缺陷問題。 resize 在開空間的同時還會進行初始化,影響 size 。

這是vs下的擴容:

reserve的優勢就在于如果我們知道要開多少空間,我們就可以一次性開好,就可以避免頻繁的擴容,因為我們知道頻繁擴容是要付出代價的,所以C++在這方面做的很好。

1.2.3 vector 增刪查改

為什么不推薦使用insert以及erase呢?因為我們知道數組刪除數據是要挪動數據的,這樣就導致花費更多時間,所以一般情況下不推薦使用。

上述內容很簡單,查網站就會使用,不過多講解,下面主要講解迭代器失效的問題;

1.2.4 vector 迭代器失效問題。(重點)
迭代器的主要作用就是讓算法能夠不用關心底層數據結構,其底層實際就是一個指針,或者是對指針進行了封裝,比如:vector的迭代器就是原生態指針T* 。因此迭代器失效,實際就是迭代器底層對應指針所指向的空間被銷毀了,而使用一塊已經被釋放的空間,造成的后果是程序崩潰(即如果繼續使用已經失效的迭代器,程序可能會崩潰)。 為什么會這樣呢? 下面我們看幾個例子:
1. 會引起其底層空間改變的操作,都有可能是迭代器失效 ,比如: resize 、 reserve 、 insert 、 assign 、push_back等。 拿擴容來說,reserve的底層實現是講原來的空間釋放掉,然后開辟新的空間,這樣迭代器所在的位置就發生了改變,所以最后就導致了迭代器失效了。 我們看看下面這段代碼:
#includeusing namespace std;
#includeint main()
{
	vectorv{ 1,2,3,4,5,6 };
	auto it = v.begin();
	v.assign(100, 3);
	//因為這里擴容過,所以迭代器肯定失效
	while (it != v.end())
	{
		cout<< *it<< " ";
		++it;
	}
	cout<< endl;
	return 0;
}

結果正如我們所料:

解決這個辦法就是更新一下迭代器即可正常使用。

看看其他例子:

2. 指定位置元素的刪除操作--erase
int main()
{
	int a[] = { 1, 2, 3, 4 };
	vectorv(a, a + sizeof(a) / sizeof(int));
	// 使用find查找3所在位置的iterator
	vector::iterator pos = find(v.begin(), v.end(), 3);
	// 刪除pos位置的數據,導致pos迭代器失效。
	v.erase(pos);
	cout<< *pos<< endl; // 此處會導致非法訪問
	return 0;
}
erase 刪除 pos 位置元素后, pos 位置之后的元素會往前搬移, 沒有導致底層空間的改變,理論上講迭代器不應該會失效 ,但是: 如果pos剛好是最后一個元素,刪完之后pos剛好是end的位置,而end位置是沒有元素的,那么pos就失效了。因此刪除vector中任意位置上元素時,vs就認為該位置迭代器失效了。 我們可以看到 vs實現的方式是比較嚴格的 ,如果不更新迭代器這就無法使用了。后面我們會模擬實現vector,后面我們模擬實現的就可以使用。 如果要 刪除vector中所有的偶數,我們應該怎么做呢? 下面這樣就是有問題的:
int main()
{
	vectorv{ 1, 2, 3, 4 };
	auto it = v.begin();
	while (it != v.end())
	{
		if (*it % 2 == 0)
			v.erase(it);
		++it;
	}

	return 0;
}

不難發現這里肯定是有問題的,因為刪除完4之后it又++就已經越界訪問了。

我們可以在不是偶數的時候再++,同時更新一下it,是偶數的就不用++

int main()
{
	vectorv{ 1, 2, 3, 4 };
	auto it = v.begin();
	while (it != v.end())
	{
		if (*it % 2 == 0)
			it = v.erase(it);
		else
		{
			++it;
		}
	}
	for (auto& e : v)
	{
		cout<< e<< endl;
	}
	return 0;
}

但是在Linux底下g++編譯器就沒有檢查的那么嚴格:

看看擴容這段代碼:

// 1. 擴容之后,迭代器已經失效了,程序雖然可以運行,但是運行結果已經不對了
int main()
{
	vectorv{ 1,2,3,4,5 };
	for (size_t i = 0; i< v.size(); ++i)
		cout<< v[i]<< " ";
	cout<< endl;
	auto it = v.begin();
	cout<< "擴容之前,vector的容量為: "<< v.capacity()<< endl;
	// 通過reserve將底層空間設置為100,目的是為了讓vector的迭代器失效 
	v.reserve(100);
	cout<< "擴容之后,vector的容量為: "<< v.capacity()<< endl;

	// 經過上述reserve之后,it迭代器肯定會失效,在vs下程序就直接崩潰了,但是linux下不會
	// 雖然可能運行,但是輸出的結果是不對的
	while (it != v.end())
	{
		cout<< *it<< " ";
		++it;
	}
	cout<< endl;
	return 0;
}

可以看到Linux底下是沒有報錯的,因為空間還是原來的空間,后序元素往前搬移了,it的位置還是有效的,但是對于剛剛那個偶數那題Linux下也會報錯:

4. 與vector類似,string在插入+擴容操作+erase之后,迭代器也會失效

最后說說如何解決這類問題:

迭代器失效解決辦法:在使用前,對迭代器重新賦值即可 1.2.5 vector 在OJ中的使用

因為數組在實際的應用非常廣泛,所以C++的vector的運用也是非常多,而且嵌套vector遠遠比C語言中的二維數組好用,下面我們就來看看vector在oj中的應用:

1. 力扣
這題楊輝三角實現起來其實并不是很難,但是如果使用C語言來做就很難受了,因為開辟空間那里就會讓你非常頭疼,但是對于C++來說這又不是一件難事了。這里就體現了嵌套vector的優點了。 思路: 先開辟好一個vector>,這樣相當于C語言中的二維數組了。然后調整好空間,在第一行以及對角線的那一行初始化為1,其他的初始化為0,然后我們就可以遍歷這個嵌套vector,判斷是否0的元素,是就讓其加上上一行的前一個以及上一行的那個。
實現方式:
class Solution {
public:
    vector>generate(int numRows) {
        //先開辟空間
        vector>vv;
        vv.resize(numRows);
        for(size_t i= 0 ;i

2.力扣

這道題如果使用哈希表的話就超出了這個空間復雜度了,用暴力查找的方式又不符合題意,這里有一個思路非常巧妙:

我們可以利用位運算來解決,因為這個除了這個數字其他的數字都出現過3次,我們可以把數組中的每一個數字的二進制位加起來,然后讓結果%3就可以得到我們所想要的二進制位了,(不論是0還是1,%3的結果都是我們想要的那個數的二進制位),最后我們用ret每次接受一下要的到二進制位,就可以得到答案。

代碼實現:

class Solution {
public:
    int singleNumber(vector& nums) {
        //我們可以把所有的二進制位全部加起來,然后%3就可以得到所求的數字的二進制位了
        int ret = 0;//我們要求的數字
        for(int i = 0;i<32;++i)
        {
            int sum = 0;
            for(auto e:nums)
            {
                sum += ((e>>i) & 1);
            }
            //把要求的數字的二進制位找出來
            if(sum%3)
            {
                ret |= (1<

3.數組中出現次數超過一半的數字_牛客題霸_牛客網

思路:因為所出現的元素的個數超過了一般半,我們就可以通過計數的方式記錄它,如果是這個元素就++,不是就--,最后得到的那個數一定是我們想要的數,另外,我們還可以拓展一下:如果這個數不一定存在那要怎么處理?

我們可以對這個記錄一下這個數,然后再遍歷一次數組,通過計數的方式去確認是否存在。

代碼實現:

class Solution {
public:
    int MoreThanHalfNum_Solution(vectornumbers) {
    //因為所出現的元素的個數超過了一般半,我們就可以通過計數的方式記錄它,如果是這個元素就++,不是就--
    //這樣的話就可以在最后的時候找到這個元素
    int tmp = numbers[0];//記錄我們要求的數據
    int times = 1;
    for(int i = 1;i

4.力扣

這一題的難度比較大,運用到了回溯算法

思路:

我們可以通過一個數組來記錄數字與字母之間的映射關系,然后利用回溯算法(遞歸)就解決像這種組合問題,下面通過這題來大概講解一下回溯:

這個很像二叉樹的遍歷,但又復雜一點,這個可以看成多叉樹的遍歷方式。我們可以通過每一層的遞歸來達到一個組合的效果。

代碼實現:

class Solution {
    //映射數組
    string numstr[10] = {"","","abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"};
public:
    //遞歸子函數
    void combine(string& digits,int i,vector& vcombine,string retstr)
    {
        if(i == digits.size())
        {
            vcombine.push_back(retstr);
            return;
        }
        //找到對應的字母
        int num = digits[i]- '0';
         string str = numstr[num];
         //遍歷串中的所有字符,然后進入下一層
         for(auto ch:str)
         {
             combine(digits,i+1,vcombine,retstr+ch);
         }
    }
    vectorletterCombinations(string digits) {
        vectorvcombine;
        if(digits.empty())
        {
            return vcombine;
        }
        int i = 0;
        string retstr;//用來每次加,然后最后加到vcombine中 
        //遞歸
        combine(digits,i,vcombine,retstr);
        return vcombine;
    }
};

下面通過畫遞歸展開圖再來看看其中的細節:

2.vector深度剖析及模擬實現 使用memcpy拷貝問題
1. memcpy是內存的二進制格式拷貝,將一段內存空間中內容原封不動的拷貝到另外一段內存空間中 2. 如果拷貝的是自定義類型的元素, memcpy 既高效又不會出錯,但 如果拷貝的是自定義類型元素,并且自定義類型元素中涉及到資源管理時,就會出錯,因為memcpy的拷貝實際是淺拷貝。

這個和之前講拷貝構造的時候很像,都是淺拷貝導致的問題。?可能會引起內存泄漏甚至程序崩潰。

動態二維數組理解

在前面就已經看過了二維數組的題了,這里不過多介紹,還是介紹一下memcpy也會使內存崩潰的結果:

要解決這個問題,我們還是要進行深拷貝,這是下面的reserve的模擬實現代碼來解決這個問題:

我們可以通過這個一個對象賦值的方式來進行深拷貝

模擬實現vector:
templateclass vector
    {
    public:
        // Vector的迭代器是一個原生指針
            typedef T* iterator;
            typedef const T* const_iterator;

            iterator begin()
            {
                return _start;
            }
            iterator end()
            {
                return _end;
            }
            const_iterator cbegin()
            {
                return _start;
            }
            const_iterator cend() const
            {
                return _end;
            }

            // construct and destroy

            vector()
                :_start(nullptr)
                ,_end(nullptr)
                ,_endOfStorage(nullptr)
            {}

            vector(int n, const T& value = T())
                :_start(nullptr)
                , _end(nullptr)
                , _endOfStorage(nullptr)
            {
                reserve(n);
                for (int i = 0; i< n; ++i)
                {
                    push_back(value);
                }
            }

            templatevector(InputIterator first, InputIterator last)
                :_start(nullptr)
                , _end(nullptr)
                , _endOfStorage(nullptr)
            {
                while (first != last)
                {
                    push_back(*first);
                    ++first;
                }
            }

            vector(const vector& v)
                :_start(nullptr)
                , _end(nullptr)
                , _endOfStorage(nullptr)
            {
                //找個工具人
                vectortmp(v._start, v._end);
                swap(tmp);
            }

            vector& operator= (vectorv)
            {
                swap(v);
                return *this;
            }

            ~vector()
            {
                delete[] _start;
                _start = _end = _endOfStorage = nullptr;
            }

            // capacity

            size_t size() const
            {
                return _end - _start;
            }

            size_t capacity() const
            {
                return _endOfStorage - _start;
            }

            void reserve(size_t n)
            {
                //堅持不縮容
                if (n >capacity())
                {
                    //開辟新的空間,然后賦值過去
                    T* tmp = new T[n];
                    size_t oldsize = size();
                    if (_start)
                    {
                        for (size_t i = 0; i< oldsize; ++i)
                        {
                            tmp[i] = _start[i];
                        }
                        delete[]_start;
                    }
               
                    _start = tmp;
                    _end = _start + oldsize;
                    _endOfStorage = _start + n;
                }
            }

            void resize(size_t n, const T& value = T())
            {
                //要擴容
                if (n >capacity())
                {
                    int newcapacity = capacity() == 0 ? 4 : 2 * capacity();
                    reserve(newcapacity);
                }
    
                if (n >size())
                {
                    while (_end != _start + n)
                    {
                        push_back(value);
                    }
                }
                else
                {
                    _end = _start + n;
                }
            }



            ///access///

            T& operator[](size_t pos)
            {
                assert(pos< size());
                return _start[pos];
            }

            const T& operator[](size_t pos)const
            {
                assert(pos< size());
                return _start[pos];
            }



            ///modify/

            void push_back(const T& x)
            {
                if (size() == capacity())
                {
                    int newcapacity = capacity() == 0 ? 4 : 2 * capacity();
                    reserve(newcapacity);
                }
                *_end = x;
                ++_end;
            }

            void pop_back()
            {
                assert(_end >_start);
                --_end;
            }

            void swap(vector& v)
            {
                std::swap(_start, v._start);
                std::swap(_end, v._end);
                std::swap(_endOfStorage, v._endOfStorage);
            }

            iterator insert(iterator pos, const T& x)
            {
                assert(_start<= pos);
                assert(_end >pos);
                //判斷增容
                int distance = pos - _start;
                if (_end == _endOfStorage)
                {
                    int newcapacity = capacity() == 0 ? 4 : 2 * capacity();
                    reserve(newcapacity);
                    //這里的擴容不處理會導致迭代器失效
                    pos = _start + distance;
                }
                //挪動數據,插入
                auto end = _end -1;
                while (end >= pos)
                {
                    *(end+1) = *end;
                    --end;
                }
                *pos = x;
                ++_end;
                return pos;
            }

            iterator erase(iterator pos)
            {
                assert(pos >= _start);
                assert(pos< _end);
                //挪動數據
                iterator  ret = pos + 1;
                while (ret< _end)
                {
                    *(ret - 1) = *ret;
                    ++ret;
                }
                --_end;
                return pos;
            }

    private:
        iterator _start; // 指向數據塊的開始
        iterator _end; // 指向有效數據的尾
        iterator _endOfStorage; // 指向存儲容量的尾
    };

其中實現過程中最容易錯誤的就是insert以及erase擴容問題,這是最容易出錯的。

擴容是防止淺拷貝,所有把利用賦值來實現深拷貝。insert以及erase要注意更新迭代器,防止迭代器失效。

你是否還在尋找穩定的海外服務器提供商?創新互聯www.cdcxhl.cn海外機房具備T級流量清洗系統配攻擊溯源,準確流量調度確保服務器高可用性,企業級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧

網頁題目:C++vector-創新互聯
網站路徑:http://www.yijiale78.com/article6/dddpog.html

成都網站建設公司_創新互聯,為您提供建站公司網站排名營銷型網站建設Google云服務器網站制作

廣告

聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯