喜歡的朋友可以關注收藏一下: http://blog.csdn.NET/qq_31201973
本文如有錯誤,請及時私信我。
原版要求:
創建一個list容器,放置6個整型數值[0, 1, 30, 20, 10, 0]
1. 從後向前打印出容器內的元素
2. 向list容器後面添加兩個元素,並對容器內的值求和並打印
3. 打印鏈表的中間元素
4. 找到不爲0的元素,複製到一個vector中並打印vector元素
根據要求需要兩種容器,還需要輸入輸出所以包含了三個頭文件,所以我搭起了這樣的框架
#include<iostream>
#include<list>
#include<vector>
using namespace std;
typedef list<int> INTLIST;
int main()
{
system("pause");
return 0;
}
然後是存6個元素到list,倒着打印。這個地方我爲了防止打印的時候當掉用了plist = --(L.end())。限定條件沒有寫,因爲如果寫迭代器不等於begin的話會少打印一個元素。
INTLIST L{0,1,30,20,10,0};
INTLIST::iterator plist;
cout << "1. 從後向前打印出容器內的元素." << endl;
for (plist = --(L.end());; --plist) //for無限定條件時不判斷
{
cout << *plist << " ";
if (plist == L.begin()) //在此處判斷並不影響效率
{
break;
}
}
第一問就解決了,第二問要求添加兩個元素後求和,添加元素用push_back,求和用c++ 新標準的for循環,因爲要做+ - 所以 auto後面要加引用
cout << endl << endl << "2. 向list容器後面添加兩個元素,並對容器內的值求和並打印." << endl;
cout << "請任意輸入兩個int類型數字:";
for (i = 0; i < 2; ++i)
{
cin >> a;
L.push_back(a);
}
for (auto& plist : L)
{
sum+=plist;
}
cout << "list容器內" << L.size() << "個元素的和爲:" << sum << endl << endl;
但是這個程序有個bug就是如果超過int的範圍會越過循環,一開始我本來要採取上週的辦法解決,但是發現問題層出不禁,具體看我的註釋
while (a < -2147483647 || a > 2147483647) //int範圍邊界的判斷,經測試實際範圍應該是-2147483648~2147483647。
{//但是加判斷里加負號以後會顯示錯誤 1 error C4146: 一元負運算符應用於無符號類型,結果仍爲無符號類型。
//這一問題是由於編譯器SDL安全檢查認爲這一操作(通常是爲無符號整形取負的操作)無效而產生的.
//當編譯器看到2147483648時會自動認爲超過了2147483647,直接轉換成unsigned int.當編譯器看到負號的時候直接取反是它本身,編譯器存不了那麼大的數,詳細看一元運算符。
cout << "整數(int)範圍非法,請重新輸入整數(int -2147483648~2147483647):";
cin >> a;
}
最後我還用函數清了一下緩存區,結果也不理想,最後我只能把變量定義爲long long int 來緩解這個問題
cout << endl << endl << "2. 向list容器後面添加兩個元素,並對容器內的值求和並打印." << endl;
cout << "請任意輸入兩個int類型數字:";
for (i = 0; i < 2; ++i)
{
cin >> a;
while (a < -2147483647 || a > 2147483647) //int範圍邊界的判斷,經測試實際範圍應該是-2147483648~2147483647。
{//但是加判斷里加負號以後會顯示錯誤 1 error C4146: 一元負運算符應用於無符號類型,結果仍爲無符號類型。
//這一問題是由於編譯器SDL安全檢查認爲這一操作(通常是爲無符號整形取負的操作)無效而產生的.
//當編譯器看到2147483648時會自動認爲超過了2147483647,直接轉換成unsigned int.當編譯器看到負號的時候直接取反是它本身,編譯器存不了那麼大的數,詳細看一元運算符。
cout << "整數(int)範圍非法,請重新輸入整數(int -2147483648~2147483647):";
cin >> a;
}
L.push_back(a);
}
for (auto& plist : L)
{
sum+=plist;
}
cout << "list容器內" << L.size() << "個元素的和爲:" << sum << endl << endl;
第三個問題實際上就是迭代器和計數器的應用,我也採取了快慢指針的做法,雖然效率要比傳統快慢指針要慢,但是減少了循環次數
cout << "3. 打印鏈表的中間元素" << endl;
if ((L.size()) % 2 == 0) //如果是偶數用速度會少循環一般次數
{
i = (L.size()) / 2; //中間元素這裏默認是中間靠前的一個,這樣無論容器元素是偶數還是奇數都適用;
for (plist = L.begin();; ++++plist) //有點類似於快指針,雖然少循環了一半的次數,但不是嚴格意義上的快指針,嚴格意義快指針是fast=fast->next->next; ,速度稍微快一點。
{
----i;
if (i == 0)
{
cout << "中間元素爲:" << *plist << endl << endl; //打印的是第四個元素L{0,1,30,20,10,0,輸入元素1,輸入元素2} ,如果總元素是8個,那應該打印第4個,30 !!!
break; //防止再進入接下來的循環
}
}
}
else
{
i = (L.size()) / 2; //中間元素這裏默認是中間靠前的一個,這樣無論容器元素是偶數還是奇數都適用;
for (plist = L.begin();; ++plist)
{
--i;
if (i == 0)
{
cout << "中間元素爲:" << *plist << endl << endl; //打印的是第四個元素L{0,1,30,20,10,0,輸入元素1,輸入元素2} ,如果總元素是8個,那應該打印第4個,30 !!!
break; //防止再進入接下來的循環
}
}
}
那爲什麼++++plist不是快指針,而是調用了兩次呢,我用斷點做了這樣的實驗
第一張圖是從標準庫截取的,它在運行到for循環時候,++重載運行了兩次,這就說明並不是傳統的快指針。
同時我還發現++i --i 比 i++ i-- 速度要快,因爲前者少了一步,標準庫的代碼如下
_Myiter& operator++()
{ // preincrement
++(*(_Mybase *)this);
return (*this);
}
_Myiter operator++(int)
{ // postincrement
_Myiter _Tmp = *this;
++*this;
return (_Tmp);
}
_Myiter& operator--()
{ // predecrement
--(*(_Mybase *)this);
return (*this);
}
_Myiter operator--(int)
{ // postdecrement
_Myiter _Tmp = *this;
--*this;
return (_Tmp);
}
};
這樣來看如果循環次數較多那麼效率差別就很大。
第四問其實沒東西就是遍歷過程中判斷,插入,然後打印出來
cout << "4. 找到不爲0的元素,複製到一個vector中並打印vector元素" << endl;
for (auto plist: L)
{
if (plist != 0)
{
V.push_back(plist);
}
}
cout << "不爲0的元素已經插入到vector中,共" << V.size() << "個元素." << endl;
cout << "vector中的元素爲:";
for (auto pvector : V)
{
cout << pvector << " ";
}
cout << endl << endl;
整個的實現就是這樣,下面附完整源代碼:
// main.cpp
#include<iostream>
#include<list>
#include<vector>
using namespace std;
typedef list<int> INTLIST;
int main()
{
INTLIST L{0,1,30,20,10,0};
INTLIST::iterator plist;
int sum = 0, i;
long long int a;
vector<int> V;
vector<int>::iterator pvector = V.begin();
cout << "1. 從後向前打印出容器內的元素." << endl;
for (plist = --(L.end());; --plist) //for無限定條件時不判斷
{
cout << *plist << " ";
if (plist == L.begin()) //在此處判斷並不影響效率
{
break;
}
}
cout << endl << endl << "2. 向list容器後面添加兩個元素,並對容器內的值求和並打印." << endl;
cout << "請任意輸入兩個int類型數字:";
for (i = 0; i < 2; ++i)
{
cin >> a;
while (a < -2147483647 || a > 2147483647) //int範圍邊界的判斷,經測試實際範圍應該是-2147483648~2147483647。
{//但是加判斷里加負號以後會顯示錯誤 1 error C4146: 一元負運算符應用於無符號類型,結果仍爲無符號類型。
//這一問題是由於編譯器SDL安全檢查認爲這一操作(通常是爲無符號整形取負的操作)無效而產生的.
//當編譯器看到2147483648時會自動認爲超過了2147483647,直接轉換成unsigned int.當編譯器看到負號的時候直接取反是它本身,編譯器存不了那麼大的數,詳細看一元運算符。
cout << "整數(int)範圍非法,請重新輸入整數(int -2147483648~2147483647):";
cin >> a;
}
L.push_back(a);
}
for (auto& plist : L)
{
sum+=plist;
}
cout << "list容器內" << L.size() << "個元素的和爲:" << sum << endl << endl;
cout << "3. 打印鏈表的中間元素" << endl;
if ((L.size()) % 2 == 0) //如果是偶數用速度會少循環一般次數
{
i = (L.size()) / 2; //中間元素這裏默認是中間靠前的一個,這樣無論容器元素是偶數還是奇數都適用;
for (plist = L.begin();; ++++plist) //有點類似於快指針,雖然少循環了一半的次數,但不是嚴格意義上的快指針,嚴格意義快指針是fast=fast->next->next; ,速度稍微快一點。
{
----i;
if (i == 0)
{
cout << "中間元素爲:" << *plist << endl << endl; //打印的是第四個元素L{0,1,30,20,10,0,輸入元素1,輸入元素2} ,如果總元素是8個,那應該打印第4個,30 !!!
break; //防止再進入接下來的循環
}
}
}
else
{
i = (L.size()) / 2; //中間元素這裏默認是中間靠前的一個,這樣無論容器元素是偶數還是奇數都適用;
for (plist = L.begin();; ++plist)
{
--i;
if (i == 0)
{
cout << "中間元素爲:" << *plist << endl << endl; //打印的是第四個元素L{0,1,30,20,10,0,輸入元素1,輸入元素2} ,如果總元素是8個,那應該打印第4個,30 !!!
break; //防止再進入接下來的循環
}
}
}
cout << "4. 找到不爲0的元素,複製到一個vector中並打印vector元素" << endl;
for (auto plist: L)
{
if (plist != 0)
{
V.push_back(plist);
}
}
cout << "不爲0的元素已經插入到vector中,共" << V.size() << "個元素." << endl;
cout << "vector中的元素爲:";
for (auto pvector : V)
{
cout << pvector << " ";
}
cout << endl << endl;
cout << "經測試程序結果符合要求." << endl << endl;
system("pause");
return 0;
}
運行截圖: