C++自修入門實境秀、C++ Primer 5版研讀秀 59/ ~ v9循序容器圓滿-20191008_115707



9.6容器轉接器

程式庫定義了3個適配器(轉接器(adaptor)):

In addition to the sequential containers, the library defines three sequential container adaptors: stack , queue , and priority_queue .

An adaptor is a general concept in the library.

There are container, iterator, and function adaptors.

Essentially, an adaptor is a mechanism for making one thing act like another.

這個「another」就是適配器(adaptor)或容器轉接器(container adaptor)本身所代表的(類似「委派」的相反。委派是我該做什麼不做,找別人做;而轉接器(適配器)則是我雖然不是它,但是我代它做)又委派可能是相同型別才行;而轉接器或適配器(adaptor)則是不同型別間的「委派」。

A container adaptor takes an existing container type and makes it act like a different type. For

For example, the stack adaptor takes a sequential container (other than array or forward_list) and makes it operate as if it were a stack .



13:20

A 表示 Adaptor

所以中文能力您說重不重要嘛!

Each adaptor supports all the relational operators: ==, !=,-<,<=,>, >=. These operators return the result of comparing the underlying containers

這些運算子會回傳比較底層容器的結果。

→這樣會易讓人誤會「比較」是修飾「底層」這個形容詞的副詞。要改作文嘛!應改為:

這些運算子會回傳底層容器比較後的結果。

Table 9.17. Operations and Types Common to the Container Adaptors

通用於所有容器轉接器(container adaptor)的運算操作和型別成員

表9.17 :容器轉接器共通的運算和型別

size_type 大到足以容納這個型別最大的物件之大小的型別。

value_type 元素型別。

container_type 轉接器在其上實作的底層容器之型別。

A a; 創建一個名為a的空轉接器。

A a(c); 以容器c的一個拷貝創建一個新的轉接器,名為a。

關係運算子 每個轉接器都支援所有的關係運算子:==、!=、<、<=、>、>=。這些

運算子會回傳比較底層容器的結果。

a.empty() 如果a有任何元素,就為false,否則為true。

a.size() a中的元素數目。

swap(a, b)

a.swap(b) 對調a和b的內容;a與b必須有相同的型別,包括它們在其上實作的

容器之型別。

Defining an Adaptor

定義一個轉接器

34:40

每個容器轉接器都定義了二個建構器:

1.預設建構器(default constructor)建構了一個空的物件

2.帶了一個容器作為引數的建構器,會用這個容器引數來以拷貝的方式初始化這個剛建構的轉接器(adaptor)。可以說是拷貝初始化。

For example, assuming that deq is a deque<int> , we can use deq to initialize a new stack as follows:

stack<int> stk(deq); // copies elements from deq into stk

可見 轉接器就是能帶著那個引數的東西,做到那個引數原型做不到的事情

此例就是讓deq可以做到stack能做的事情

簡單地來講,轉接器它就是把「<元素型別>」左邊的容器型別抽換掉!

拷貝初始化(copy initialize)

直接初始化(direct initialize)見Direct and Copy Forms of Initialization 初始化的直接和拷貝形式(頁84)

1:33:00

By default both stack and queue are implemented in terms of deque , and a priority_queue is implemented on a vector .

預設情況下,stack與queue都是以deque為基礎來實作的,而priority_queue則是在一個vector上實作的。我們可以覆寫預設的容器型別,只要在創建轉接器時,指名一個循序容 器作為第二個型別引數就行了:

// empty stack implemented on top of vector

stack<string, vector<string>> str_stk;

// str_stk2 is implemented on top of vector and initially holds a copy of svec

stack<string, vector<string>> str_stk2(svec);

頁370

什麼容器用在什麼轉接器上是有所限制的

1:40:00

All of the adaptors require the ability to add and remove elements.

所有的適配器(轉接器)都必須有增減元素的能力

轉接器(adaptor)是不能採用array與forward_list這兩種容器的

all of the adaptors require operations that add, remove, or access the last element in the container.

所有的轉接器都需要有加、減及存取最後一個元素的能力(要能對容器內最後一個元素的存取與增減能力)然而「back() 對 forward_list 無效」

3:12:00

因為forward_list,只有_after類的運算操作,而最後一個元素的after是不存在的,所以不能在最後一個元素上進行操作,也就無法對其做存取的動作了。(參見前9.3.4. Specialized forward_list Operations頁350-351)

stack

stack 轉接器(adaptor)只需要三種運算:

A stack requires only push_back, pop_back , and back operations,

queue

queue轉接器則不能由vector來建構:

The queue adaptor requires back, push_back, front , and push_front , so it can be built on a list or deque but not on a vector .

Priority_queue

priority_queue則不能用list來建構(建置):

A priority_queue requires random access in addition to the front, push_back , and pop_back operations; it can be built on a vector or a deque but not on a list .

2:13:10

Stack Adaptor

堆疊轉接器(Stack Adaptor)

可見stack這種轉接器也是種型別:

The stack type is defined in the stack header.

Table 9.18. Stack Operations in Addition to Those in Table 9.17

表9.18 :除了表9.17中以外的其他堆疊運算

s.pop()

預設使用deque,也能在list或vector上實作。

從stack移除最頂端的元素,但不回傳。

s.push(item)

s.emplace(args) 藉由拷貝或移動item,在stack上創建一個新的頂端元素,或從

args建構出該元素。

s.top() 回傳stack頂端的元素,但不回傳。



中文版又翻錯:

Returns, but does not remove, the top element on the stack.

回傳stack頂端的元素,但不回傳。

→移除。

2:26:40

stack<int> intStack; // empty stack

// fill up the stack

for (size_t ix = 0; ix != 10; ++ix)

intStack.push(ix); // intStack holds 0 ... 9 inclusive

while (!intStack.empty()) { // while there are still values in intStack

int value = intStack.top();

// code that uses value

intStack.pop(); // pop the top element, and repeat

}

2:29:40

以上實例其實只是stack當作容器在操作,與適配器(adaptor)轉接器(adaptor)應該無關

2:34:00

頁371

每個容器轉接器都根據了它的底層容器型別的運算,而有一組自己的運算

這種運算並沒有繼承關係,在轉接器上是不能用底層容器型別的運算的

Each container adaptor defines its own operations in terms of operations provided by the underlying container type.

We can use only the adaptor operations and cannot use the operations of the underlying container type. For example,

intStack.push(ix); // intStack holds 0 ... 9 inclusive

calls push_back on the deque object on which intStack is based. Although stack is implemented by using a deque , we have no direct access to the deque operations. We cannot call push_back on a stack; instead, we must use the stack operation named push .

我們不能在一個stack上呼叫push_back,我們必須使用名為push的stack運算(來取代)。

英文句式(習慣)與中文不同,如這裡「instead」可以不翻,要翻則翻在句末才合中文習慣(慣例、文法、語法),不宜直接用字典義「取而代之」來套入翻譯

2:49:00



The Queue Adaptors

佇列轉接器

「佇」→當作「貯」比較對。但應是把它看成人在排隊(如課本中用餐廳與顧客作例子),所以才用「佇」字。

The queue and priority_queue adaptors are defined in the queue header.

Table 9.19 lists the operations supported by these types.

可見轉接器(adaptor)都是型別

3:00:00

forward_list複習



3:55:00

Table 9.19. queue, priority_queue Operations in Addition to Table 9.17

表 9.19 :表 9.17 以外的 queue 和 priority_queue 運算

預設情況下,queue 使用 deque 而 priority_queue 使用 vector ;

queue 也能使用 list 或 vector,priority_queue 能使用一個 deque。

q.pop() 從queue移除,但不回傳,前端的元素,或從priority_queue移除 (但不回傳)最高優先序的元素。

q.front()

q.back() 回傳,但不移除,q的前端或後端元素。只對queue有效。

q.top () 回傳,但不移除,最高優先序的元素。只對priority_queue有效。

q.push(item)

q.emplace(args) 在queue的尾端或priority_queue中適當的位置創建一個帶有值item的元素,或從args建構出元素來。



4:4:30

queue 就是先進先出(FIFO)

從後面進(加入元素)從前面出(移除元素)

priority queue

A restaurant that seats people according to their reservation time, regardless of when they arrive, is an example of a priority queue.



優先序佇列(priority queue)

練習9.52

4:17:18

4:24:30

#include<string>

#include<iostream>

#include<deque>

#include<stack>

using namespace std;

int main() {

string s;

deque<string> deqs;

stack<string>::size_type ix(0), pos(0);

while (cin >> s)

{

deqs.push_back(s);

}

stack<string> stks(deqs);//原來轉接器(adaptor)就是這樣用的啊!

//就是請stack來執行deqs做不到的事,就把deqs當作引數交給它(複製一份;傳值;copy)讓轉接器做原來容器(container)做不到的事,使得容器表現得好像跟轉接器一樣

for (string s : deqs)//range for 轉接器(adaptor)不能用

{

if (s == "("||s.find("(")!=string::npos)

pos = ix;

if (s == ")"||s.find("(") != string::npos)

{

for (stack<string>::size_type i = 0; i != (deqs.size()- pos); ++i)

{

stks.pop();

}

stks.push("●parenthesized expression was replaced.●");

break;

}

++ix;

}

}

果然 轉接器的概念就跟委派一樣:不必事必躬親。能教人代做的,就請人代做

頁372

Chapter Summary

5:12:00

The library containers are template types that holds objects of a given type.

In a sequential container, elements are ordered and accessed by position.

轉接器非循序容器,就無法藉由位置來存取。

The sequential containers share a common, standardized interface: If two sequential containers offer a particular operation, then the operation has the same interface and meaning for both containers.

這些循序容器都使用一個共通的標準界面:如果兩個循序容器提供一個特定的運算,那麼該運算對這兩個容器而言,會有相同的介面和意義。

所謂動態記憶體管理就是如 capacity() reserve() resize() shrink_to_fit()這些成員函式在做的

All the containers (except array ) provide efficient dynamic memory management.

所有的容器(array除外)都提供有效率的動態記憶體管理。

因為array是回定大小的,所以不涉及記動態憶體的管理

5:28:40

Both vector and string provide more detailed control over memory management through their reserve and capacity members.

capacity 和 reserve 只對 vector 和 string 有效

5:31:59

For the most part大部分情況下, the containers define surprisingly few 極其有限的operations.

大多數情況下,容器定義的運算都出乎意料的少。

中文程度比一比

5:34:59

其他有用(實用、好用)的運算,如排序與搜尋,卻是由標準演算法(standard algorithms)來定義的:

Other useful operations, such as sorting or searching, are defined not by the container types but by the standard algorithms, which we shall cover in Chapter 10.

5:46:00

adaptor

Library type, function, or iterator that, given a type, function, or iterator, makes it act like another.

循序容器的轉接器有三種:

There are three sequential container adaptors: stack, queue, and priority_queue.

Each adaptor defines a new interface on top of an underlying sequential container type.

每個轉 接器都是在一個底層的循序容器型別上定義了一個新的介面。

所謂的介面就是包括了一些介面函式,如pop()、push()等,讓類別使用者可以去操作的東西、運用的資源,就叫介面。

5:55:30

begin、end

容器型別如果是const,傳回的迭代器就會是const

deque

deque裡頭的元素也可以藉由位置的索引值來存取

Like a vector in all respects except that it supports fast insertion and deletion at the front of the container as well as at the back and does not relocate elements as a result of insertions or deletions at either end.

在這兩端插入或删除後,不會調動其元素的位置。

不會由於兩端的插入或刪除而重新定位元素(google翻譯)

和vector很像,只不過還能在首位(前端)快速新增和刪除元素;而且在首尾兩端插入或刪除元素後並不需要重新配置記憶體位置。



forward_list

forward_list Sequential container that represents a singly linked list 單向連結串列. Elements in a forward_list may be accessed only sequentially;

頁373

starting from a given element, we can get to another element only by traversing each element between them.

Iterators on forward_list do not support decrement ( -- ).

當然不支援--,不能backward(倒車)

支援對任何點元素的快速插入與移除

Unlike other containers, insertions and deletions occur after a given iterator position.

它處理的都它所在位置的後面(右邊)那個元素

對元素的插入與移除,對它其內的迭代器並不會有影響:

Iterators remain valid when new elements are added. When an element is removed, only the iterators to that element are invalidated.

iterator range (迭代器範圍)

left-inclusive interval (左包含區間)

list

所謂雙向連結、單向連結(forward_list)串列(list)的連結概念,即若「聯結車」(Linked car、Coupled train)的意思。指一個接一個(像火車)連結起來,所以是有方向性的。

火車聯結車有時也是雙向都可作火車頭的,就是list這類型

和forward_list一樣,新增與刪除元素並不會影響到迭代器(iterator)的有效性

6:32:40

off-the-beginning iterator (開端前迭代器)

queue

其實循序容器的轉接器就好像循序容器的「外掛」(增益集)一樣,增益其循序容器所不能的運算與操作。

也可以說是「增強版」,增強了循序容器的運算或操作

所以翻成「增益器」「強化器」也可以

為什麼用「adapt」就是讓它適應力更強,更能適用在更多的地方



6:44:00

sequential container (循序容器)

循序容器的元素都是同一個型別:

Type that holds an ordered collection of objects of a single type.

其內元素都是藉由位置來存取的

stack

只可以由一端來新增、移除元素

Adaptor for the sequential containers that yields a type that lets us add and remove elements from one end only.

Vector

We can efficiently add or remove vector elements only at the back.

Adding elements to a vector might cause it to be reallocated, invalidating all iterators into the vector .

Adding (or removing) an element in the middle of a vector invalidates all iterators to elements after the insertion (or deletion) point.

留言

熱門文章