1. 程式人生 > >基礎演算法之vector、回溯

基礎演算法之vector、回溯

基礎演算法之vector、回溯

一.vector

vector介紹

vector 是C++ STL的一個重要成員,使用它時需要包含標頭檔案:#include ,我對它的理解就是一個動態陣列,如果你需要一個數組,又不知道它的長度是多少,vector是一個好的資料結構。

  • 特點
    1.順序序列
    2.動態陣列
    3.記憶體分配
    vector有兩個函式:
    capacity(),返回物件緩衝區(vector維護的記憶體空間)實際申請的空間大小。
    size(),返回當前物件緩衝區儲存資料的個數。
    對於vector來說,capacity是永遠大於等於size的,capacity和size相等時,vector就會擴容,capacity變大。

vector的常用方法

1.初始化

  • 定義一個向量:
    vector< typename>name;
    Typename可以是int,char,double,也可以是vector型vector<vector >name;//> >之間要加空格。這個相當於是一個二維陣列。

  • (1)vector< int>a;預設初始化
    (2)vector< int>a(10);//定義了10個整型元素的向量(尖括號中為元素型別名,它可以是任何合法的資料型別),但沒有給出初值,其值是不確定的。
    (3)vector< int>a(10,1);//定義了10個整型元素的向量,且給出每個元素的初值為1
    (4)vector< int>a(b);//用b向量來建立a向量,整體複製性賦值
    (5)vector< int>a(b.begin(),b.begin+3);//定義了a值為b中第0個到第2個(共3個)元素
    (6)int b[7]={1,2,3,4,5,9,8};
    vector< int>a(b,b+7);//從陣列中獲得初值

  • 函式:begin(),end(),front(),back()
    begin() 得到陣列頭的指標
    end() 得到陣列的最後一個單元+1的指標
    front() 得到陣列頭的引用
    back() 得到陣列的最後一個單元的引用

  //1.1 預設初始化
 vector<int> v;
 out_vector(v);
cout << v.back() << endl;
    // 1.2 賦予長度,預設是0
vector<int> v(n);
out_vector(v);
    // 1.3 初始化長度,和預設值
vector<int> v(n, 1);
out_vector(v);
    // 1.4 用另一個向量初始化
vector<int> w;
for(int i=0;i<5;i++){
       w.push_back(i);
           }
    out_vector(w);
    vector<int> v(w);
    out_vector(v);
    w.push_back(1);
   cout << "w add a element." <<endl;
    out_vector(w);
    out_vector(v);
    // 1.5 用另一個向量的一部分來初始化
    vector<int> w;
   for(int i=0;i<5;i++){
       w.push_back(i);
    }
   out_vector(w);
   vector<int> v(w.begin(), w.begin() + 3);
   out_vector(v);
    // 1.6 用陣列的一部分來初始化
int a[] = {0,1,2,3,4,5,6,7,8};
vector<int> v(a, a+4);
out_vector(v);

2.模擬棧

  • a.push_back(5); //在a的最後一個向量後插入一個元素,其值為5
    a.back(); //返回a的最後一個元素
    a.pop_back(); //刪除a向量的最後一個元素
vector<int> v;
for(int i=0;i<n;i++){
    v.push_back(i);
    cout << "push:" << i << endl;
}
out_vector(v);
for(int i=0;i<n;i++){
    int t = v.back();
    v.pop_back();
    cout << "pop:" << t << endl;
}
out_vector(v);

3.模擬佇列

  • a.front(); //返回a的第一個元素
    a.erase(a.begin()+1,a.begin()+3); //刪除a中第1個(從第0個算起)到第2個元素,也就是說刪除的元素從a.begin()+1算起(包括它)一直到a.begin()+3(不包括它)
vector<int> v;
    for(int i=0;i<n;i++){
        v.push_back(i);
        cout << "push:" << i << endl;
    }
    out_vector(v);
    for(int i=0;i<n;i++){
        int t = v.front();
        v.erase(v.begin());
        cout << "pop:" << t << endl;
    }
    out_vector(v);

4.遍歷

  • 1.通過下標讀取
vector<int> v;
    for(int i=0;i<n;i++){
        v.push_back(i);
        cout << "push:" << i << endl;
    }
    out_vector(v);
    for(int i=0;i<n;i++){
        int t = v.front();
        v.erase(v.begin());
        cout << "pop:" << t << endl;
    }
    out_vector(v);
  • 2.通過迭代器讀取

for(vector<int>::iterator it = v.begin(); it != v.end(); it ++){
        cout << *it << " ";
    }
    cout << endl;

for (vector<int>::reverse_iterator it = v.rbegin(); it!= v.rend(); it++) {
        cout << *it << " ";
    }
    cout <<endl;

5.插入指定元素

  • 1.insert(a.begin()+1,5); //在a的第1個元素(從第0個算起)的位置插入數值5,如a為1,2,3,4,插入元素後為1,5,2,3,4
  • 2.insert(a.begin()+1,3,5); //在a的第1個元素(從第0個算起)的位置插入3個數,其值都為5
  • 3.insert(a.begin()+1,b+3,b+6); //b為陣列,在a的第1個元素(從第0個算起)的位置插入b的第3個元素到第5個元素(不包括b+6),如b為1,2,3,4,5,9,8,插入元素後為1,4,5,9,2,3,4,5,9,8
int a[] = {1,2,3,4,4,5,6,7};
    vector<int> v(a, a+sizeof(a)/sizeof(int));
    out_vector(v);
    cout << "在第1個元素後面插入10:" <<endl;
    v.insert(v.begin()+1, 10);
    out_vector(v);
    cout << "在倒數第2個元素前插入a[1]~a[5]" << endl;
    v.insert(v.end()-2, a+1, a+6);
    out_vector(v);

6.刪除指定元素

  • 1.earse(a.begin()); //刪除第一個元素
  • 2.erase(a.begin()+1,a.begin()+3); //刪除a中第1個(從第0個算起)到第2個元素,也就是說刪除的元素從a.begin()+1算起(包括它)一直到a.begin()+3(不包括它)
int a[] = {1,2,3,4,4,5,6,7};
    vector<int> v(a, a+sizeof(a)/sizeof(int));
    out_vector(v);
    cout << "刪除第3個元素:" <<endl;
    v.erase(v.begin()+2);
    out_vector(v);
    cout << "刪除第2~3個元素:" <<endl;
    v.erase(v.begin()+1, v.begin()+3);
    out_vector(v);

7.交換兩個vector

  • a.swap(b); //b為向量,將a中的元素和b中的元素進行整體性交換

8.其他幾種重要的algorithm庫方法

使用時需要包含標頭檔案:#include

  • 1.sort(a.begin(),a.end()); //對a中的從a.begin()(包括它)到a.end()(不包括它)的元素進行從小到大排列
  • 2.reverse(a.begin(),a.end()); //對a中的從a.begin()(包括它)到a.end()(不包括它)的元素倒置,但不排列,如a中元素為1,3,2,4,倒置後為4,2,3,1
  • 3.copy(a.begin(),a.end(),b.begin()+1); //把a中的從a.begin()(包括它)到a.end()(不包括它)的元素複製到b中,從b.begin()+1的位置(包括它)開始,覆蓋掉原有元素
  • 4.find(a.begin(),a.end(),10); //在a中的從a.begin()(包括它)到a.end()(不包括它)的元素中查詢10,若存在返回其在向量中的位置

二.回溯

排列組合數

  • 排列,輸入一個數組,輸出A(n, m)的所有可能
    輸入的第一行第一個數代表n,第二個數代表m
    例如:
    輸入:
    3 2
    2 5 6
    輸出:
    2 5
    2 6
    5 2
    5 6
    6 2
    6 5
    在這裡插入圖片描述

在這裡插入圖片描述

在這裡插入圖片描述

  • 程式碼
#include <iostream>
#include <vector>

using namespace std;
/**
* a是原陣列,大小是n
* mpt是每次記錄的陣列,大小是m
* visit是記錄是否被訪問過,大小是n
* n是a的長度
* m是排列的長度
* cur是mpt遍歷到的位置
* pre是上一次mpt[cur]取的位置
* v是輸出,記錄所有的排列組合
* &v 此處是引用的使用,否則不會改變v
*/
void dfs_rank(int a[], int mpt[], int visit[], int n, int m, int cur, int pre, vector<vector<int> > &v){
    // 如果當前遍歷到第m個數了,則輸出
    if (cur == m) {
        vector<int> r(m);
        for (int i=0;i<m;i++) {
            r[i] = a[mpt[i]];
            //cout << a[mpt[i]] << " ";
        }
        //cout << endl;
        v.push_back(r);
        return ;
    }
    // 組合,則把遍歷的起始位置改成int i = pre,if語句中的pre = i解註釋即可
    for(int i=0;i<n;i++){
        // 如果沒有訪問過,則使用
        if(visit[i] == 0){
            // 使用當前可用位置
            visit[i] = 1;
            // 記錄在mpt中
            mpt[cur] = i;
            // 記錄上一次記錄在mpt中的位置
            pre = i;
            // 迭代
            dfs_rank(a, mpt, visit, n, m, cur+1, pre, v);
            // 當前位置使用完畢,置為可用狀態
            visit[i] = 0;
        }
    }
}

int main(){
    // 原陣列
    int a[] = {2,5,6,7,8};
    // 陣列長度
    int n = sizeof(a)/sizeof(int);
    // 排列的長度
    int m = 3;
    // 標記該位置的元素是否被訪問過
    int visit[n] = {0};
    // 儲存當前的排列
    int mpt[m] = {0};
    // 儲存所有的排列
    vector<vector<int> > v;
    // 當前遍歷到a中第幾個元素了 0<=cur<m
    int cur = 0;
    // 排列方法中沒用,在求組合數時候記錄上一次儲存的數的位置
    // int pre = 0;
    // 呼叫方法,
    dfs_rank(a, mpt, visit, n, m, cur, pre, v);
    // 列印
    for (int i=0;i<v.size();i++) {
        for(int j=0;j<v[i].size();j++){
            cout << v[i][j] << " ";
        }
        cout << endl;
    }
    return 0;

n皇后

#include <iostream>
#include <cmath>

using namespace std;
/**
* n皇后問題
* 問題描述:任意兩個皇后都不能處於同一行、同一列或同一斜線上,請問有多少中擺法。
* 輸出可行解的個數
*/

/**
* 判斷當前排列是否符合規則
*/
void judge_is_nHuangHou(int mpt[], int n, int &ans){
    // f表示符合規則
    bool f = true;
    for(int i=0;i<n;i++){
        for(int j=i+1;j<n;j++){
            // 如果在同一列或者在同一對角線的元素的表示不符合規則,跳出本層迴圈
            if(mpt[i] == mpt[j] || abs(mpt[i]-mpt[j])==abs(i-j)){
                f = false;
                break;
            }
        }
        // 不符合規則則跳出迴圈,跳出外層迴圈
        if(!f)break;
    }
    // 如果符合規則則計數加一
    if(f){
        ans ++;
    }
}

/**
* 檢查當前皇后cur是否可以放在x位置
*/
bool is_place(int mpt[], int cur, int x){
    bool f = true;
    for(int i=0;i<cur;i++){
        if(abs(mpt[i]-x)==abs(cur-i)){
            f = false;
            break;
        }
    }
    return f;
}

/**
* 遞歸回溯
* mpt[] 記錄每次的記錄,表示第i個皇后放在mpt[i]的位置上
* visit[] 表示當前位置是否被訪問過
* n為皇后的數量
* cur為當前皇后
* ans為計數器
*/
void dfs_nHuangHou(int mpt[], int visit[], int n, int cur, int &ans){
    // 如果皇后全部遍歷,則進行判斷
    if(cur == n){
        for(int i=0;i<n;i++){
            cout << mpt[i] << " ";
        }
        cout << endl;
        // 判斷當前排列是否符合規則
        judge_is_nHuangHou(mpt, n, ans);
        return ;
    }
    // 遍歷所有的位置
    for(int i=0;i<n;i++){
        // 如果當前位置還沒有被使用
        if (visit[i] == 0) {
            // 判斷當前位置是否符合規則,不符合則跳過當前位置
            if(!is_place(mpt, cur, i))continue;
            // 使用當前位置
            visit[i] = 1;
            // cur號皇后放在i位置
            mpt[cur] = i;
            // 繼續查詢下一皇后的位置
            dfs_nHuangHou(mpt, visit, n, cur+1, ans);
            // 使用完成,置為可用
            visit[i] = 0;
        }
    }
}

int main(){
    // 皇后的數量
    int n = 8;
    // 計數器
    int ans = 0;
    // 記錄每次合適的排列位置
    int mpt[n] = {0};
    // 記錄是否訪問過
    int visit[n] = {0};
    // 呼叫方法
    dfs_nHuangHou(mpt, visit, n, 0, ans);
    // 輸出計數
    cout << ans << endl;
    return 0;
}

方格填數問題

  • 題目描述:
    如下的10個格子
    在這裡插入圖片描述
    填入0~9的數字。要求:連續的兩個數字不能相鄰。例如1和2不能相鄰
    (左右、上下、對角都算相鄰)
    一共有多少種可能的填數方案?
  • 程式碼
#include <iostream>
#include <cmath>

using namespace std;
/**
* 方格填數問題
* 問題描述:填入0~9的數字。要求:連續的兩個數字不能相鄰。(左右、上下、對角都算相鄰)
* 輸出可行解的個數
*/

/**
* 判斷當前排列是否符合規則
*/
void judge_boxfill(int flag[][4], int mpt[][4], int n, int m, int &ans){
    // 標記,true為該排列符合規則
    bool f = true;
    // 4個方向,右,右下,下,左下
    int dir[][2] = {{0,1},{1,1},{1,0}
            
           

相關推薦

基礎演算法vector回溯

基礎演算法之vector、回溯 一.vector vector介紹 vector的常用方法 1.初始化 2.模擬棧 3.模擬佇列 4.遍歷 5.插入指定元素 6.刪除指定元素

基礎演算法貪心法二分法及其他演算法思想和技巧

基礎演算法學習筆記(三) 1. 貪心法 1.1 簡單貪心 1.2 區間貪心 2. 二分法 2.1 二分查詢 2.2 快速冪 3. two pointers 3.1 什麼是two

算法基礎知識二叉樹,

pan rect nbsp 結構 src class wiki 子節點 資料 一、樹 把它叫做“樹”是因為它看起來像一棵倒掛的樹,也就是說它是根朝上,而葉朝下的。在計算機科學中,樹(英語:tree)是一種抽象數據類型(ADT)或是實作這種

算法基礎知識二叉樹

image inline cstyle width var mar span mes med 一、樹 把它叫做“樹”是因為它看起來像一棵倒掛的樹,也就是說它是根朝上,而葉朝下的。在計算機科學中,樹(英語:tree)是一種抽象數據類型(AD

python基礎知識列表元祖字典/字符串。

case 文字 cas star 索引 常見 ali num nta 基礎知識之列表: 列表用 [ ]來定義是可變的,可以通過索引值來去查詢裏面的字段可以可以追加,刪除。 常用用法如下 names = [‘zhang‘, ‘zhuang‘, [‘alx‘, ‘bob

python基礎知識列表元祖字典集合字符串。

終端 mes ror sort names int 字母 基礎知識 ndt 1.可變類型之列表 列表用 [ ]來定義是可變的,可以通過索引值來去查詢裏面的字段可以可以追加,刪除等 ```python names=‘zhangyang guyun xiangpeng xuli

java基礎學習函式陣列

1、函式 1、函式的定義 函式是定義在類中有特定功能的一小段程式,也稱方法。定義格式: 修飾符 返回值型別 函式名(引數型別 形式引數1,引數型別 形式引數2, ) { 執行語句; return 返回值; } 2、功能 定義函式可以對功能程式碼進行封裝,提高程式碼的複用性

Java基礎常量變數運算子

資料型別 : Java中的基本型別功能簡單,不具備物件的特性,為了使基本型別具備物件的特性,所以出現了包裝類,就可以像操作物件一樣操作基本型別資料。 基本型別對應的包裝類 基本型別 byte int short long float double boolean char 包裝型別

Java基礎順序選擇迴圈結構

程式流程  java程式語句執行的順序包括4種基本控制結構:順序結構、選擇結構、迴圈結構、異常處理邏輯結構。 順序結構  Java程式中,語句執行的基本順序按各語句出現的位置先後順序執行,即為順序結構。 例1:順序結構:已知三角形三邊,求三角形面積: pub

JavaScript基礎概念----call()apply()bind()

它們都是可以改變this的指向。 call和apply都是改變上下文中的this並立即執行這個函式, call()和apply()的區別就在於,兩者之間的引數。 bind方法可以讓對應的函式想什麼時候調就什麼時候呼叫,並且可以將引數在執行的時候新增 var o = {} function fu

基礎演算法:與異或運算 與異或運算

與、或、異或運算   1.與運算(&) 參加運算的兩個資料,按二進位制位進行“與”運算。 運算規則:0&0=0;   0&1=0;    1&0=0; 

C語言資料結構與演算法深度廣度優先搜尋

一、深度優先搜尋(Depth-First-Search 簡稱:DFS) 1.1 遍歷過程:   (1)從圖中某個頂點v出發,訪問v。   (2)找出剛才第一個被頂點訪問的鄰接點。訪問該頂點。以這個頂點為新的頂點,重複此步驟,直到訪問過的頂點沒有未被訪問過的頂點為止。   (3)返回到

排序演算法冒泡選擇快速插入

基本資料型別的賦值過程:值傳遞(傳遞的是值得拷貝) 資料交換的三種形式: 不需要第三方變數 a = a+b  b = a-b    a = a-b 引用第三方變數  temp = a  a = b  b = tem

MySQL基礎系列 DDLDML和DCL的區別與理解

此文章主要介紹SQL資料庫的DDL、DML和DCL的區別與理解 一、DDL(data definition language) 資料定義語言,用於操作物件和物件的屬性 DDL用於操作物件和物件的屬性,這種物件包括資料庫本身,以及資料庫物件,像:表、檢視等等,DDL對這些物件和屬性的管理和

基礎演算法排序雜湊遞迴

基礎演算法學習筆記(一) 一. 選擇排序 1.選擇排序(Selection sort)是一種簡單直觀的排序演算法。它的工作原理如下。首先在未排序序列中找到最小(大)元素,存放到排序序列的起始位置,然後,再從剩餘未排序元素中繼續尋找最小(大)元素,然後放到已排序序列的末尾。以此類推,直

【Python】python 基礎語法列表n維陣列的變換(取反(逆序)\切片等)

【筆記】 二維陣列取反: 執行a[::-1],上下行交換。同樣的看成一維陣列的話,一行就是一個元素。 執行a[:, ::-1],上下前後交換。相當於對行取逆序,對列取逆序。 a=np.arange(12).reshape(3,4) a array([[ 0, 1, 2, 3],

JAVA常用演算法冒泡選擇快速

排序:對一組資料進行從小到大(或從大到小)的順序排列。 排序演算法有很多種,這裡介紹Java中面試經常出現的三種排序方式:冒泡、選擇、快速。 冒泡: 顧明思義,是氣泡從液體的底部到頂部的過程,就像串糖葫蘆一樣,先決定最下面的資料。在演算法的過程中是把一組資

Java基礎知識StringStringBuilder和StringBuffer三者的區別

String、StringBuilder和StringBuffer這三個類在操作字串時主要有執行速度和執行緒安全這兩方面的區別: 1.執行速度   執行速度,即執行字串操作時程式碼執行的時間快慢,在這方面執行速度快慢為:StringBuilder > StringBuffer >

python基礎知識整除取餘冪運算

數字和表示式python直譯器可以當作計算器使用>>>2+2 4整數除法一個整數被另一個整數除,計算結果的小數部分被截去,只保留整數部分。如果參與除法的兩個數中有一個為浮點數,運算結果為浮點數。>>>1/2 0 >>>1.

機器學習提升演算法AdaboostGBGBDT與XGBoost演算法

一、提升演算法概論 Boosting(提升)是一族可將弱學習器提升為強學習器的演算法。提升演算法基於這樣一種思想:對於一個複雜的任務,將多個專家的判斷總和得出的結果要比任何一個專家單獨的判斷好。這族演算法的工作機制類似:先從初始訓練集訓練出一個基學習器,再根據基學習器表現