20160203.CCPP體系詳解(0013天)

尹成發表於2016-02-16

程式片段(01):陣列.c+02.陣列初始化語法.c
內容概要:陣列

///01.陣列.c
#include <stdio.h>
#include <stdlib.h>

//01.採用容器結構儲存資料的要點:
//  1.必須為每個資料分配獨立的儲存空間
//  2.必須為每個資料分配獨立的識別符號(變數名稱)
//02.C語言之C99語法的特點:
//  針對於VC編譯器:
//      1.VC編譯器分配陣列的時候必須靜態分配
//          靜態分配:在編譯時期確定陣列所佔據的記憶體尺寸(位元組數)大小
//      2.陣列長度必須為真常量(或常量表示式)
//          明確的陣列元素個數
//  針對於GCC編譯器:
//      1.GCC編譯器分配陣列的時候採用動態分配
//          動態分配:在執行時期確定陣列所佔據的記憶體尺寸
//      2.陣列長度可以為偽常量(或變數)
//          不確定的陣列元素個數(程式執行時期知道)
//03.偽常量的宣告方式:
//  在原始變數的前面新增一個偽常量標識字首("const")
//04.關於常量的透徹分析:
//  偽常量:const int num = 1;
//      1.具備記憶體實體:
//          不允許直接進行修改,但允許間接進行修改
//      2.靜態分配:
//          在編譯時期確定偽常量的值
//  真常量:#define NUM 1
//      1.不具備記憶體實體:
//          既不允許直接修改,也不允許間接修改
//      2.預編譯決定:
//          在預編譯時期就已經決定了將巨集名為了常量(整型,實型,字元型,字串型)
int main01(void)
{
    const int num = 10;//常量表示式{但是該常量表示式的常量值可以經過間接改變,所以是偽常量}-->有記憶體實體
    #define NUM 1//真常量{一旦確定了真常量的值,就不允許修改真常量的資料}-->無記憶體實體

    //int a[num];//編譯的時候確定大小,靜態分配,VC不支援
    int a[NUM];
    //VC必須靜態分配,GCC可以動態分配

    system("pause");
}

//05.關於陣列使用的要點總結:
//  1.靜態陣列分配方式:
//      (1).int a[5] = {1, 2, 3, 4, 5};//陣列元素的型別:int;陣列整體的名稱:a;陣列元素的個數:5;
//          陣列元素的具體資料:1, 2, 3, 4, 5
//      (2),靜態分配:在編譯時期就已經確定了陣列所佔用的記憶體地址以及記憶體尺寸(首地址+尺寸)
//  2.分配方式組成分析:
//      (1).int:表明陣列當中所儲存的每個元素的型別
//      (2).a:表示陣列整體的名稱(陣列名)
//          陣列名的本質是一個常量指標(偽常量)
//      (3).{}:程式碼塊兒分配方式,只能用於宣告陣列的同時進行使用(既可以區域性初始化也可以全部初始化)
//  3.sizeof:
//      (1).是一個關鍵字,而不是一個函式
//      (2).如果傳遞的是陣列名,那麼求取的記憶體尺寸是陣列整體所佔用的記憶體尺寸(區分陣列整體和陣列元素)
//  4.%p和%d的使用意義:
//      (1).所以資料在記憶體當中的儲存實質都一樣,都是二進位制資料
//      (2).格式控制符只是決定了不同的解析方式:
//          %d:記憶體資料按照有符號十進位制(signed int)型別進行解析
//          %p:記憶體資料按照指標意義進行解析
//  5.陣列元素以及陣列元素的地址:
//      a[i]:a[i]表示陣列元素的名稱,直接寫陣列元素的名稱,相當於訪問該陣列元素本身(資料)
//          好比叫一個人的名字,目的就是為了這個人知道
//      &a[i]:&表示根據變數的名稱(記憶體實體)獲取該變數的地址
//          變數的名稱:其實就是記憶體實體的別名(區分:(變數:記憶體實體)-->(變數名稱:變數別名))
//          統稱:變數(統一)-->具稱:變數別名(唯一)
//      說明:中括號"[]"的優先順序高於取記憶體實體地址符"&"的優先順序
int main02(void)
{
    //0,1,2,3,4
    int a[5] = { 1,2,3,4,5 };//a:陣列名稱,a代表該陣列的記憶體首地址

    printf("%d \n", sizeof(a));//sizeof(a):用於獲取陣列所佔用的真實記憶體尺寸(位元組大小)
    printf("%p \n", a);//陣列的記憶體首地址
    for (int i = 0; i < 5; i++)
    {
        printf("%d, %p \n", a[i], &a[i]);//i:索引;&:符號表示獲取變數的記憶體首地址
    }

    system("pause");
}

//06.陣列元素本身(記憶體實體)和陣列元素地址(記憶體實體地址)
//  1.陣列元素地址(記憶體實體地址)
//      &a[i],a+i:陣列預設從第0個開始進行索引劃分(陣列元素(記憶體實體)的識別符號:索引)
//  2.陣列元素本身(記憶體實體):
//      a[i],*(&a[i]),*(a+i)
int main03(void)
{
    //陣列宣告語法:double a[10];陣列元素的型別 陣列整體的名稱[陣列元素的個數];
    double a[10] = { 1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0 };

    printf("%d \n", sizeof(a));//10*8=80
    for (int i = 0; i < 10; i++)
    {
        //&a[i], a + i;//代表陣列第i個元素的記憶體實體地址,等價關係a+i(與型別密切相關)//以0作為開頭
        //a + (i - 1)*sizeof(double);//以1作為開頭
        //*號表示根據記憶體實體的地址獲取記憶體實體本身(資料內容)
        //a[i], *(&a[i]), *(a + i);//效果等價
        printf("%lf, %lf, %lf, %p, %p \n", a[i], *(&a[i]), *(a + i), &a[i], a + i);//下標,索引
    }

    system("pause");
}
///02.陣列初始化語法.c
#include <stdio.h>
#include <stdlib.h>

//01.陣列的初始化方式:
//  標準方式:
//      int a[5] = {1, 2, 3, 4, 5};
//      陣列元素的型別 陣列整體的名稱[陣列元素的指明個數] = {靜態初始化的靜態資料};
//  簡化方式:
//      itn a[] = {1, 2, 3, 4, 5};
//  注意事項:
//      1.C/C++當中的靜態陣列必須進行靜態初始化才能進行使用,Java當中的靜態陣列會進行預設初始化
//          大括號:{}就是表明靜態初始化
//      2.陣列的宣告必須明確兩點:陣列元素的資料型別+陣列元素的元素個數-->才能確定陣列整體尺寸(記憶體位元組數)
//      3.賦值特點:
//          (1).大括號這種靜態初始化方式,只能適用於宣告陣列的狀態下(宣告並定義的情況之下)
//          (2).統一賦值與指明賦值特點:
//              統一賦值:{0}
//              指明賦值:
//                  完全賦值:
//                      {1, 2, 3, 4, 5}
//                  前置區域性:
//                      {1, 2, 3}-->後面預設被編譯器初始化為0,只有當前面進行了指明初始化的情況,後面才會進行預設初始化為0的操作
//      4.訪問特點:
//          訪問陣列整體的內部某個元素本身(記憶體實體本身),不會出錯
//          訪問陣列整體的外部某個元素本身(記憶體實體本身),可能出錯,可能不出錯(關鍵是看系統是否為該記憶體實體分配了使用許可權)
int main04(void)
{
    //int a[10] = { 0 };//C/C++當中的陣列必須進行初始化
    //int a[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };//明確陣列初始化元素個數,可以省略陣列元素個數的宣告
    //int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };//陣列初始化不允許越界
    //int a[10] = { 1, 2, 3, 4 };//預設沒有初始化值的陣列元素都將會被預設的初始化為0
    int a[5] = { 0 };//陣列必須明確其元素個數

    for (int i = 0; i < 10; i++)
    {//注意不存在長度部分的資料將會是無法預料的值,5之後的資料可能會出現問題
        printf("%d \n", a[i]);
    }

    system("pause");
}

//02.陣列名稱的操作:
//  1.任何指標進行加法,乘法,除法都沒有任何實際意義
//  2.在同一個陣列當中的不同記憶體實體的記憶體地址進行
//      減法運算具備實際意義,用於獲取兩個陣列元素之間的元素個數差值
//  3.C語言的常規陣列不能進行整體操作,元素本身(記憶體實體)可以進行整體操作
//  4.C語言的特殊素組(字元陣列),如果以'\0'結尾,那麼就是一個正常的字串模擬
//      字串結尾識別符號必須是'\0'(字元\0)-->0或者'\0'都一樣
//      字元:'\0'-->ASCII:0-->以及關鍵字NULL
int main05(void)
{
    int a[5] = { 1, 2, 3, 4, 5 };
    int b[5] = { 2, 3, 4, 5, 6 };

    //a = b;//陣列名稱:標識陣列整體的記憶體空間,陣列名稱是一個常量指標,不可以直接進行修改
    //a[1];//訪問整體陣列a當中的第1個元素所對應的記憶體實體(資料本身)
    //a + b;//C語言當中的普通陣列不可以進行批量草最,只能針對於某一個元素進行批量操作
    //a < b;
    char str[5] = { 'c', 'a', 'l', 'c', NULL };   
    printf("%s \n", str);

    system("pause");
}

程式片段(02):01.陣列.c+02.陣列實戰.c
內容概要:陣列實戰

///01.陣列.c
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//01.陣列越界問題分析;
//  1.採用陣列名稱訪問記憶體實體的時候:
//      如果該記憶體實體位於陣列整體當中的某個部分,那麼訪問正確
//      如果該記憶體實體位於陣列整體外部的某個部分,那麼訪問出錯
//          因為作業系統並沒有為當前程式當中的陣列分配該整體陣列外部的記憶體實體的訪問許可權
//  2.C語言編譯器的特點所導致:
//      陣列不越界一定不會出錯,陣列越界可能會出錯(編譯通過但是執行不一定通過)
int main01(void)
{
    //陣列越界不一定出錯,但是不越界一定不會發生記憶體訪問衝突
    int a[5] = { 1, 2, 3, 4, 5 };

    for (int i = 0; i < 10; ++i)
    {
        printf("%d \n", a[i]);//存在越界的情況,但是C語言的編譯器不一定會進行報錯
    }

    //當採用陣列方式訪問到別處記憶體地址所對應的記憶體實體(資料本身)的時候,可能會出現報錯的情況:
    //  因為該記憶體地址在賦值之前就已經具備了一定記憶體實體(資料本身),不允許緊急性陣列操作
    //  因為作業系統並沒有為本程式分配該記憶體地址的使用許可權
    a[102389898] = 1;

    system("pause");
}

int main02(void)
{
    int a[10] = { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1 };

    for (int i = 9; i > -1; --i)
    {//逆序輸出陣列記憶體實體(資料本身)
        printf("%d \n", a[i]);
    }

    system("pause");
}

int main03(void)
{
    int a[100] = { 0 };
    time_t te = 0;
    //unsigned int seed = (unsigned int)(time(&te));//獲取隨機數種子
    //srand(seed);//種植隨機數種子
    srand((unsigned int)(time(&te)));
    for (int i = 0; i < 100; i++)
    {//迴圈初始化方式(隨機數)
        a[i] = rand() % 300;
        printf("%d \n", a[i]);
    }

    int num = 0;
    scanf("%d", &num);
    int flag = 0;//假定找不到-->標識多數情況
    for (int i = 0; i < 100; ++i)
    if (a[num] == num)
    {
        flag = 1;//標識找到-->只要存在情況
        break;
    }
    if (flag)
        printf("找到! \n");
    else
        printf("找不到! \n");

    system("pause");
}
///02.陣列實戰.c
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

//01.最簡單,最無效率的極值獲取方式:
//  打擂演算法:極值獲取以及極值在陣列當中所對應的索引
int main04(void)
{
    time_t te = 0;
    srand((unsigned int)(time(&te)));//獲取並終止隨機數種子
    int a[20] = { 0 };
    for (int i = 0; i < 20; ++i)
    {
        a[i] = rand() % 300;//通過隨機數進行陣列的賦值
        printf("%d \n", a[i]);
    }

    int minValue = a[0];
    for (int i = 1; i < 20; ++i)     //打擂演算法:獲取極小值
        if (minValue > a[i])
            minValue = a[i];

    int maxValue = a[0];
    for (int i = 1; i < 20; i++)//打擂演算法:獲取極大值
        if (maxValue < a[i])
            maxValue = a[i];

    int minIndex1 = 0;
    int minValue1 = a[0];
    for (int i = 1; i < 20; i++)//打累演算法:獲取極小值以及極小值在陣列當中所對應的索引
        if (minValue1 > a[i])
        {
            minIndex1 = i;
            minValue1 = a[i];
        }
    printf("minIndex1 = %d, minValue1 = %d \n", minIndex1, minValue1);

    system("pause");
}

//02.最簡單的排序演算法:
//  1.選擇排序演算法
//  2.時空複雜度分析:
//      時間複雜度:n平方
//      空間複雜度:1
#define EN 20
int a[EN];//C語言全域性變數預設被初始化為0
int main05(void)
{
    time_t te = 0;
    srand((unsigned int)(time(&te)));//獲取並種植隨機數種子
    for (int i = 0; i < 20; ++i)
    {
        a[i] = rand() % 300;//給陣列進行進行隨機數賦值
        printf("%d \n", a[i]);
    }
    printf("\n");

    int gtIndex = 0;
    for (int i = 0; i < EN - 1; ++i)
    {
        gtIndex = i;
        for (int j = i + 1; j < EN; ++j)
            if (a[gtIndex] < a[j])
                gtIndex = j;
        if (i != gtIndex)
        {
            a[i] = a[i] ^ a[gtIndex];
            a[gtIndex] = a[i] ^ a[gtIndex];
            a[i] = a[i] ^ a[gtIndex];
        }
    }
    for (int i = 0; i < 20; ++i)
    {
        printf("%d \n", a[i]);
    }

    system("pause");
}

程式片段(03):main.c
內容概要:GccArray

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int num=10;
    scanf("%d",&num);
    int a[num];
    //GCC支援動態分配陣列:因此陣列的元素個數指定可以採取變數,偽常量,真常量
    //動態分配,執行的時候

    return 0;
}

程式片段(04):氣泡排序.c
內容概要:氣泡排序法

#include <stdio.h>
#include <stdlib.h>

int main01(void)
{
    int intArr[10] = { 3, 5, 18, 9, 23, 5, 2, 1, 0, 2 };
    for (int i = 0; i < 10 - 1; ++i)
    {//冒泡法求最大值:兩兩臨近的資料進行比較
        if (intArr[i] > intArr[i + 1])
        {
            intArr[i] = intArr[i] ^ intArr[i + 1];
            intArr[i + 1] = intArr[i] ^ intArr[i + 1];
            intArr[i] = intArr[i] ^ intArr[i + 1];
        }
    }
    printf("maxValue = %d \n", intArr[9]);

    system("pause");
}

int main02(void)
{
    int intArr[10] = { 3, 5, 18, 9, 23, 5, 2, 1, 0, 2 };
    for (int i = 0; i < 10 - 1; ++i)//外層迴圈,每完成一次迴圈,就有一個最值沉底
    {//冒泡法實現排序:重複進行相鄰的兩個資料比較
        for (int j = 0; j < 10 - 1 - i; ++j)//沉底的次數,決定冒到了那裡
        {
            if (intArr[j] > intArr[j + 1])//沉底
            {
                intArr[j] = intArr[j] ^ intArr[j + 1];
                intArr[j + 1] = intArr[j] ^ intArr[j + 1];
                intArr[j] = intArr[j] ^ intArr[j + 1];
            }
        }
    }
    for (int i = 0; i < 10; ++i)
    {
        printf("%d \n", intArr[i]);
    }

    system("pause");
}

程式片段(05):斐波那契.c
內容概要:斐波那契陣列法

#include <stdio.h>
#include <stdlib.h>

//01.斐波那契數列:
//  1.迴圈實現
//  2.遞迴實現
//  3.(迴圈+棧)實現
//02.陣列的使用特點:
//  模擬棧這種資料結構
//      先進後出
//  模擬佇列這種資料結構
//      先進先出
//03.如何進行遞迴加速?
//  遞迴-->迴圈+棧:可以實現遞迴加速
//04.三種實現斐波那契數列方式的速度問題:
//      (迴圈+棧)>迴圈>遞迴
int fibonacciLoop(int nItem)
{//迴圈實現:
    if (1 == nItem || 2 == nItem)
        return 1;
    int temp1 = 1;
    int temp2 = 1;
    int nItemValue = 0;//初始化一個常數,效率更高
    for (int i = 2; i < nItem; ++i)
    {
        nItemValue = temp1 + temp2;//儲存推理結果
        temp1 = temp2;//資料往前推進
        temp2 = nItemValue;
    }

    return nItemValue;
}

int fibonacciRecursion(int nItem)
{//遞迴實現:
    if (1 == nItem || 2 == nItem)
        return 1;
    return fibonacciRecursion(nItem - 1) + fibonacciRecursion(nItem - 2);//關係表示式
}

int fibonacciLoopStack(int nItem)
{//(迴圈+棧)實現:
    int intArr[64] = { 0 };
    intArr[0] = 1;
    intArr[1] = 1;
    for (int i = 2; i < nItem; ++i)//注意陣列儲存特點
    {
        intArr[i] = intArr[i - 1] + intArr[i - 2];
    }

    return intArr[nItem - 1];
}

int main01(void)
{
    printf("loopResult = %d \n", fibonacciLoop(40));
    printf("recursionResult = %d \n", fibonacciRecursion(40));
    printf("loopStackResult = %d \n", fibonacciLoopStack(40));

    system("pause");
}

程式片段(06):迷宮1.c
內容概要:迷宮模擬

#include <stdio.h>
#include <stdlib.h>

void showIntArr(int intArr[10][10])
{//顯示二維陣列
    printf("------------------------------ \n");
    for (int i = 0; i < 10; ++i)
    {
        for (int j = 0; j < 10; ++j)
        {
            printf("%3d", intArr[i][j]);
        }
        printf("\n");
    }
    printf("------------------------------ \n");
}

//01.陣列資料的儲存特點:
//  1.所有陣列的資料在記憶體當中的儲存方式都是線性的
//  2.顯式的結果不同是由於不同維度的陣列對記憶體當中的資料的解析方式不同
int main01(void)
{
    int intArr[10][10] = {//二維陣列的圖形化初始化方式:將二維陣列當做一維陣列進行看待,該一維陣列當中的每個元素就是一行的資料資訊
        {0, 0, 0, 2, 0, 0, 0, 0, 0, 0},
        {0, 0, 2, 0, 0, 0, 0, 0, 0, 0},
        {0, 0, 2, 2, 2, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 2, 0, 0, 0, 0, 0},
        {0, 0, 0, 0, 2, 0, 0, 0, 0, 0},
        {0, 2, 2, 0, 0, 0, 0, 0, 0, 0},
        {2, 0, 0, 0, 0, 0, 0, 2, 0, 2},
        {0, 2, 2, 0, 0, 0, 2, 2, 0, 0},
        {2, 0, 0, 2, 0, 2, 0, 0, 0, 0},
        {0, 0, 0, 0, 0, 2, 0, 2, 0, 0}
    };
    showIntArr(intArr);

    int px = 0, py = 0;//點座標(預設:左上角(0,0)點)
    intArr[px][py] = 1;//根據點座標修改棋盤上對應點座標的資料實體(二維平面的資料實體修改為0)
    showIntArr(intArr);

    char ch = '\0';
    while (1)
    {
        ch = getchar();
        getchar();//吸收Enter鍵-->'\n'-->'\r\n':Win解析
        switch (ch)
        {
        case 'w'://按鍵控制
            if (px - 1 >= 0 && intArr[px][py] != 2)
            {
                intArr[px][py] = intArr[px][py] ^ intArr[px - 1][py];
                intArr[px - 1][py] = intArr[px][py] ^ intArr[px - 1][py];
                intArr[px][py] = intArr[px][py] ^ intArr[px - 1][py];
                --px;
            }
            break;
        case 's':
            if (px + 1 <= 9 && intArr[px + 1][py] != 2)
            {
                intArr[px][py] = intArr[px][py] ^ intArr[px + 1][py];
                intArr[px + 1][py] = intArr[px][py] ^ intArr[px + 1][py];
                intArr[px][py] = intArr[px][py] ^ intArr[px + 1][py];
                ++px;
            }
            break;
        case 'a':
            if (0 <= py - 1 && 2 != intArr[px][py - 1])
            {
                intArr[px][py] = intArr[px][py] ^ intArr[px][py - 1];
                intArr[px][py - 1] = intArr[px][py] ^ intArr[px][py - 1];
                intArr[px][py] = intArr[px][py] ^ intArr[px][py - 1];
                --py;
            }
            break;
        case 'd':
            if (9 >= intArr[px][py + 1] && 2 != intArr[px][py + 1])
            {
                intArr[px][py] = intArr[px][py] ^ intArr[px][py + 1];
                intArr[px][py + 1] = intArr[px][py] ^ intArr[px][py + 1];
                intArr[px][py] = intArr[px][py] ^ intArr[px][py + 1];
                ++py;
            }
            break;
        }
        showIntArr(intArr);
    }

    system("pause");
} 

程式片段(07):二分查詢法.c
內容概要:二分查詢法以及拉格朗日插值查詢

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>

//01.二分查詢法以及二分查詢法的變形:
//  1.前提條件:待查詢的陣列當中的資料必須有序
//      最好是順序排列的(從小到大進行排列)
//  2.二分查詢以及拉格朗日查詢:
//      拉格朗日查詢用於二分查詢的加速模式
#define N 1024
int binarySearch(int intArr[N], int value)
{//二分查詢法
    int minIndex = 0;
    int maxIndex = N - 1;
    int midIndex = 0;
    while (minIndex <= maxIndex)
    {
        midIndex = (minIndex + maxIndex) / 2;
        if (value == intArr[midIndex])
            return midIndex;
        else if (value < intArr[midIndex])
            maxIndex = --midIndex;
        else
            minIndex = ++minIndex;
    }

    return -1;
}

int lagrangeSearch(int intArr[N], int value)
{//拉格朗日查詢法
    int minIndex = 0;
    int maxIndex = N - 1;
    //int midIndex = 0;
    int tempIndex = 0;
    while (minIndex <= maxIndex)
    {
        //midIndex = (minIndex + maxIndex) / 2;
        //midIndex = minIndex + (maxIndex - minIndex) / 2;
        tempIndex = minIndex + (value - intArr[minIndex]) / (intArr[maxIndex] - intArr[minIndex]);//二分查詢加速
        if (value == intArr[tempIndex])
            return tempIndex;
        else if (value < intArr[tempIndex])
            maxIndex = --tempIndex;
        else
            minIndex = ++tempIndex;
    }

    return -1;
}

int main01(void)
{
    int intArr[1024] = { 0 };
    for (int i = 0; i < 1024; ++i)
        intArr[i] = i;
    int value = 0;
    scanf("%d", &value);
    printf("valueIndex = %d \n", binarySearch(intArr, value));
    printf("valueIndex = %d \n", lagrangeSearch(intArr, value));

    system("pause");
}

程式片段(08):插入排序法.c
內容概要:插入排序法

#include <stdio.h>
#include <stdlib.h>

int main01(void)
{//插值法也要求資料必須有序
    int intArr[10] = { 1, 2, 3, 4, 6, 7, 8, 9, 10, 5 };

    int tempIndex = 9;
    int tempValue = intArr[9];
    while (tempIndex > 0 && intArr[tempIndex - 1] > tempValue)//從後往前進行插值
    {   //tempIndex>0:由於要讓索引-1,但是索引-1之後必須>=0因此索引必須>=1
        //當此迴圈退出的時候,退出時所在的索引其實就是剛好需要進行插值的索引位置
        intArr[tempIndex] = intArr[tempIndex - 1];
        --tempIndex;
    }
    intArr[tempIndex] = tempValue;

    for (int i = 0; i < 10; ++i)
        printf("%3d", intArr[i]);

    system("pause");
}

#define EN 10
void insertSort(int intArr[EN])
{
    int tempIndex = 0;
    int tempValue = 0;
    //01.插值排序法說明:
    //  int i = 1:
    //      當元素個數為1的時候,不需要插值排序演算法
    //      從1開始才能便於進行插值操作intArr[index-1]=intArr[index]
    //  i < 10:
    //      從第一個元素開始,到最後一個元素都需要進行插值排序檢測
    //      注:忽略掉單個元素的陣列,因為單個元素不存在插值排序
    // tempIndex > 0:(可能插值移位的最大範圍)
    //      能夠進行插值移位的前提
    //  intArr[tempIndex - 1] > tempValue:(可能插值移位的最小範圍)
    //      只要當前索引的前一個索引所對應的值大於待插入的值
    //      就有必要執行插入操作
    for (int i = 1; i < 10; ++i)
    {
        tempIndex = i;
        tempValue = intArr[i];
        while (tempIndex > 0 && intArr[tempIndex - 1] > tempValue)
        {
            intArr[tempIndex] = intArr[tempIndex - 1];
            --tempIndex;
        }
        intArr[tempIndex] = tempValue;
    }
}

int main02(void)
{
    int intArr[EN] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 10 };
    insertSort(intArr);
    for (int i = 0; i < EN; ++i)
    {
        printf("%3d", intArr[i]);
    }

    system("pause");
}

程式片段(09):開房.c
內容概要:開房資料檢索-硬碟模式

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

char resourcesPath[256] = "D:\\Resource\\TestData\\DB\\KaiFang.txt";
char targetWritePath[256] = { 0 };

void selectResultWriteToTargetFile(char nameStr[256])
{
    sprintf(targetWritePath, "D:\\Resource\\TestData\\Test\\%s.txt", nameStr);
    FILE *frp = fopen(resourcesPath, "r");//以讀取模式開啟一個檔案(硬碟直接讀取模式)
    FILE *fwp = fopen(targetWritePath, "w");//以寫入模式開啟一個檔案(硬碟直接寫入模式)
    if (NULL == frp && NULL == fwp)
    {
        printf("建立檔案指標失敗! \n");
        return;
    }

    while(!feof(frp))//feof();到了檔案讀取的末尾返回真,沒有到檔案讀取的末尾返回假
    {//只要沒有到達檔案讀取的末尾,就繼續進行硬碟檔案讀取操作
        char readStr[1024] = { 0 };
        fgets(readStr, 1024, frp);//硬碟模式讀取一行資料(以換行符作為讀取模式結束,並且長度僅限為1024)讀取條件限制
        char *tempStr = strstr(readStr, nameStr);
        if (NULL != tempStr)
        {
            puts(readStr);//列印檢索到的資料行
            fputs(readStr, fwp);//硬碟模式寫入到指定檔案
        }
    }
    fclose(fwp);//關閉檔案寫入流
    fclose(frp);//關閉檔案讀取流
}

int main01(void)
{
    char nameStr[256] = { 0 };
    scanf("%s", nameStr);
    printf("您要查詢人的姓名是:%s \n", nameStr);

    time_t start = 0, end = 0;
    time(&start);
    selectResultWriteToTargetFile(nameStr);
    time(&end);
    printf("查詢總計話費了%lf秒 \n", difftime(end, start));
    system(targetWritePath);

    system("pause");
}

程式片段(10):二維陣列.c
內容概要:二維陣列

#include <stdio.h>
#include <stdlib.h>

//01.二維陣列:
//  1.二維陣列的記憶體儲存原理:
//      所有陣列,無論一維陣列,二維陣列,多維陣列,在記憶體當中的
//      儲存實質都是採取的連續儲存方式
//  2.二維陣列的規律賦值方式:
//      先進行行遍歷,在進行列遍歷,再逐個進行逐個陣列元素的具體賦值操作
//  3.如何求取任何陣列的記憶體尺寸?
//      都是採用sizeof();關鍵字進行的求取
int main01(void)
{
    int a[5][5];
    //1, 2, 3, 4, 5, 6, 7, 8, 9, 10:總共25個陣列元素
    printf("%d \n", sizeof(a));//sizeof(陣列名);-->求取陣列整體的記憶體尺寸5*5*4
    printf("%p \n", a);

    int num = 1;
    for (int i = 0; i < 5; ++i)
    {
        for (int j = 0; j < 5; ++j)
        {
            //a[i][j] = num;
            //++num;
            //printf("%4d", a[i][j]);
            printf("%4d", a[i][j] = num++);//複合語句
        }
    }

    system("pause");
}

//02.二維陣列知識詳解:
//  1.初始化方式:
//      統一初始化:
//          int a[5][4] = {0};-->巧用0
//      前置初始化:
//          int a[5][4] = {1}-->特用除0以外的數字
//      注:
//      1.統一初始化方式的實質還是前置初始化方式,由於採用特殊的數字
//          0進行初始化,所以整體被統一的初始化為了0
//      2.所有陣列的初始化方式特點:
//          只要陣列當中前置元素有數字前置初始化,那麼後面的陣列元素
//              本身都會被預設的初始化為0
//  2.多維陣列的特殊初始化方式:
//      多維陣列轉化為低維陣列進行初始化
//      int a[5][4] = {
//          {1, 2},
//          {1, 2, 3}
//      };
//  3.確定陣列記憶體尺寸的兩大要素:
//      陣列元素個數+陣列元素尺寸
//   注:維度的省略情況分析:自動推演
//      一維陣列的一維可以省略
//      二維陣列的一維不可以省略
//      三維陣列的二維不可以省略
int main02(void)
{
    //int a[5][4] = { 1 };//全部初始化為0
    //printf("%p \n", a);
    //int a[5][4] = { 1, 2, 3, 4, 5 };//陣列的前面賦值,後面賦值為0,預設是一行一行的進行賦值操作
    //int a[5][4] = { {1, 2, 3, 4}, {1, 2} };//二維陣列的初始化方式
    //int a[5][4] = {0};//全部初始化為0
    int a[5][4];//解釋:5個一維陣列,每個一維陣列當中儲存有4個陣列元素
    int b[2][4] = { {1,2},{3,4} };//第一個名曲有幾個一維陣列,可以進行忽略
    //行座標可以進行忽略,但是列座標不可以進行忽略
    int num = 1;
    for (int i = 0; i < 2; ++i)
    {
        for (int j = 0; j < 4; ++j)
        {
            b[i][j] = num++;
        }
    }
    printf("\n\n");
    for (int i = 0; i < 2; ++i)
    {
        for (int j = 0; j < 4; ++j)
        {
            printf("%4d", b[i][j]);
        }
    }

    system("pause");
}

//03.二維陣列的線性初始化方式:
//  奧數規律方式
//      元素個數+求模(變化慢)+求餘(變化快)+被除數是(列數)
int mai03n(void)
{
    int intArrArr[3][4];
    //規律初始化方式:
    //  00 0        01 1         02 2       03 3
    //  10 4        11 5         12 6       13 7
    //  20 8        21 9         22 10  23 11
    for (int i = 0; i < 12; ++i)//i:決定元素個數
    {
        intArrArr[i / 4][i % 4] = i;//行:變化慢;列:變化快
    }
    for (int i = 0; i < 3; ++i)
    {
        for (int j = 0; j < 4; ++j)
        {
            printf("%3d", intArrArr[i][j]);
        }
        printf("\n");
    }

    system("pause");
}

程式片段(11):迷宮初步.c+迷宮進階.c
內容概要:迷宮AI

///迷宮初步.c
#include <stdio.h>
#include <stdlib.h>

//01.關於維度與陣列的聯絡:
//  零維度:點
//      1.陣列元素
//      2.沒有方向
//  一維度:線
//      1.一維陣列
//      2.向右方向
// 二維度:面
//      1.二維陣列
//      2.上下左右
//  三維度:立體
//      1.三維陣列
//      2.上下左右前後
//  多維度:慢慢想
//      1.高維陣列
//      2.慢慢想
//      注:時間(變化)+空間(三維)
//02.所有陣列的記憶體儲存特點:
//  都是採取線性的初始方式,也就是連續儲存的方式
//  只是由於計算機對於陣列的解析方式的不同,所以產生了不同的維度效果
//03.迷宮矩陣的組成特點分析:
//  1.二維平面的迷宮矩陣由二維整型陣列進行模擬
//  2.該二微整型陣列的組成元素特點分析:
//      數字0:代表通道
//      數字2:代表牆壁
//      數字1:代表位置
//  3.移動點和結束點模擬移動:
//      移動點:(startPointX, startPointY);
//      結束點:(endPointX, endPointY);
int intArrArrMaze[5][5] = {
    { 0, 0, 2, 2, 2 },
    { 2, 0, 0, 0, 2 },
    { 2, 0, 0, 0, 2 },
    { 2, 0, 0, 0, 2 },
    { 2, 0, 0, 0, 0 },
};
int endPointX = 4, endPointY = 4;//終止點

int visitMaze(int startPointX, int startPointY);

int main(void)
{
    printf("顯示迷宮 \n");
    printf("-------------------------------------- \n");
    for (int i = 0; i < 5; ++i)
    {
        for (int j = 0; j < 5; ++j)
        {
            printf("%3d", intArrArrMaze[i][j]);
        }
        printf("\n");
    }

    int startPointX = 0, startPointY = 0;//起始點
    if (0 == visitMaze(startPointX, startPointY))
    {
        printf("迷宮沒有出口 \n");
    }
    else
    {
        printf("顯示路徑 \n");
        for (int i = 0; i < 5; ++i)
        {
            for (int j = 0; j < 5; ++j)
            {
                if (2 == intArrArrMaze[i][j])
                    printf("█");
                else if (1 == intArrArrMaze[i][j])
                    printf("◇");
                else
                    printf("  ");
            }
            printf("\n");
        }
    }

    system("pause");
}

//04.該函式的作用功能作用分析:
//  1.函式整體作用:
//      通過遞迴呼叫方式判定迷宮是否有出口?
//          如果走到終點,那麼就含有出口;如果沒能走到出口,那麼就沒有出口!
//  2.函式區域性作用:
//      每走動一次,都需要判定是否到達迷宮終點
//  3.引數說明:
//      形參值:
//          整體意義:起始點
//          區域性意義:將要走動的點-->試探點
//      返回值:
//          整體意義:是否能夠走出迷宮
//          區域性意義:判斷是否完成了一條路線
int visitMaze(int startPointX, int startPointY)
{
    int success = 0;//標識迷宮是否完成走出狀態
    int movePointX = startPointX;//通過起始點初始化移動點
    int movePointY = startPointY;
    intArrArrMaze[movePointX][movePointY] = 3;//標識該點的起始狀態:
    if (endPointX == movePointX && endPointY == movePointY)
        return success = 1;//標識成功的走出狀態
    if (1 != success && 5 > movePointY + 1 && 2 > intArrArrMaze[movePointX][movePointY + 1]) visitMaze(movePointX, movePointY + 1);
    if (1 != success && 5 > movePointX + 1 && 2 > intArrArrMaze[movePointX + 1][movePointY]) visitMaze(movePointX + 1, movePointY);
    if (1 != success && -1 < movePointY - 1 && 2 > intArrArrMaze[movePointX][movePointY - 1]) visitMaze(movePointX, movePointY - 1);
    if (1 != success && -1 < movePointY - 1 && 2 >  intArrArrMaze[movePointX - 1][movePointY]) visitMaze(movePointX- 1, movePointY);
    if (1 != success)//標識改點的回溯狀態:該點走過,但是沒有走成功,因此將該點重新值置為0
        intArrArrMaze[movePointX][movePointY] = 0;

    return success;
}
///迷宮進階.c
#include <stdio.h>
#include <stdlib.h>

//資料層(Data):儲存資料
int intArrArrMazeY[10][10] = {//原始迷宮
    { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 2, 0, 0, 0, 0, 0 },
    { 2, 2, 2, 0, 0, 2, 0, 0, 0, 0 },
    { 0, 0, 2, 0, 0, 0, 2, 0, 2, 2 },
    { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 2, 0, 0, 0, 2, 0, 2 },
    { 0, 0, 0, 0, 2, 0, 0, 2, 0, 0 },
    { 0, 0, 0, 0, 0, 2, 0, 2, 2, 0 },
    { 0, 0, 0, 0, 0, 0, 2, 2, 0, 0 }
};
int intArrArrMazeC[10][10] = {//測試迷宮
    { 1, 0, 2, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 2, 2, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 0, 2, 0, 0, 0, 0, 0 },
    { 2, 2, 2, 0, 0, 2, 0, 0, 0, 0 },
    { 0, 0, 2, 0, 0, 0, 2, 0, 2, 2 },
    { 0, 0, 2, 0, 0, 0, 0, 0, 0, 0 },
    { 0, 0, 0, 2, 0, 0, 0, 2, 0, 2 },
    { 0, 0, 0, 0, 2, 0, 0, 2, 0, 0 },
    { 0, 0, 0, 0, 0, 2, 0, 2, 2, 0 },
    { 0, 0, 0, 0, 0, 0, 2, 2, 0, 0 }
};
int endPointX = 9, endPointY = 9;
int countCiNum = 1;

//檢視層(View):顯示資料
void showMaze(int intArrArrMaze[10][10])
{
    printf("%d------------------------------ \n", countCiNum++);
    for (int i = 0; i < 10; ++i)
    {
        for (int j = 0; j < 10; ++j)
        {
            printf("%2d", intArrArrMaze[i][j]);
        }
        printf("\n");
    }
}

//控制層(Controller):資料操作
void operateMaze(char direction, int startPointX, int startPointY)
{
    switch (direction)
    {
    case 'w':
        if (-1 < startPointX - 1 && 2 != intArrArrMazeC[startPointX - 1][startPointY])
        {
            intArrArrMazeC[startPointX][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX - 1][startPointY];
            intArrArrMazeC[startPointX - 1][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX - 1][startPointY];
            intArrArrMazeC[startPointX][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX - 1][startPointY];
        }
        break;                                                                                              
    case 's':
        if (10 > startPointX + 1 && 2 != intArrArrMazeC[startPointX + 1][startPointY])
        {
            intArrArrMazeC[startPointX][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX + 1][startPointY];
            intArrArrMazeC[startPointX + 1][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX + 1][startPointY];
            intArrArrMazeC[startPointX][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX + 1][startPointY];
        }
        break;
    case 'a':
        if (-1 < startPointY - 1 && 2 != intArrArrMazeC[startPointX][startPointY - 1])
        {
            intArrArrMazeC[startPointX][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX][startPointY - 1];
            intArrArrMazeC[startPointX][startPointY - 1] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX][startPointY - 1];
            intArrArrMazeC[startPointX][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX][startPointY - 1];
        }
        break;
    case 'd':
        if (10 > startPointY + 1 && 2 != intArrArrMazeC[startPointX][startPointY + 1])
        {
            intArrArrMazeC[startPointX][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX][startPointY + 1];
            intArrArrMazeC[startPointX][startPointY + 1] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX][startPointY + 1];
            intArrArrMazeC[startPointX][startPointY] = intArrArrMazeC[startPointX][startPointY] ^ intArrArrMazeC[startPointX][startPointY + 1];
        }
        break;
    default :
        break;
    }
    showMaze(intArrArrMazeC);
}

//業務層(Service/AI層):人工智慧
//  組成特點分析:
//      返回值:int
//          整體意義:迷宮是否能夠走通
//          區域性意義:沒有完成一條通路,就繼續往下走
//              不斷的進行壓棧,壓到樹狀遞迴的底部
//              如果不行:如果該路不通,就進行回溯釋放函式所佔用的棧記憶體(返回值無意義)
//              如果能行:如果該路暢通,就進行回溯釋放函式做佔用的棧記憶體(返回值有意義)
//      形參值:
//          int intArrArrMaze[10][10]:
//              整體意義:待測試的迷宮資料
//              區域性意義:每次迷宮的下一步,所依賴的上一步迷宮資料佈局
//          int startPointX, int startPointY:
//              整體意義:就是迷宮的起始點
//              區域性意義:就是迷宮每次要試探的下一點
int mazeAI(int intArrArrMaze[10][10], int startPointX, int startPointY)
{
    int successFlag = 0;
    int movePointX = startPointX; //測試假定起始點的正確性
    int movePointY = startPointY;
    intArrArrMaze[startPointX][startPointY] = 3;//試探迷宮走步(測試點成功走出)-->假定起點成功
    if (endPointX == movePointX && endPointY == movePointY)//當前待移動的點所在的位置
    {
        printf("小夥子恭喜走出來了! \n");
        return successFlag = 1;
    }
    //右下左上
    //  1 != successFlag:
    //      這條語句表明還沒有形成完整的通路,因此急需尋找,最終尋找到的通路
    //      一定是每一個遞迴函式都返回1的情況
    //  2 > intArrArrMaze[movePointX][movePointY + 1]:
    //      這條語句的作用既可以排除掉牆壁點,也可以排除走過點
    if (1 != successFlag && 10 > movePointY + 1 && 2 > intArrArrMaze[movePointX][movePointY + 1])  mazeAI(intArrArrMaze, movePointX, movePointY + 1);
    if (1 != successFlag && 10 > movePointX + 1 && 2 > intArrArrMaze[movePointX + 1][movePointY])  mazeAI(intArrArrMaze, movePointX + 1, movePointY);
    if (1 != successFlag && -1 < movePointY - 1 && 2 > intArrArrMaze[movePointX][movePointY - 1]) mazeAI(intArrArrMaze, movePointX, movePointY - 1);
    if (1 != successFlag && -1 < movePointX - 1 && 2 > intArrArrMaze[movePointX - 1][movePointY]) mazeAI(intArrArrMaze, movePointX - 1, movePointY);
    if (0 == successFlag)//根據樹狀遞迴,遞迴到樹狀的根部返回情況決定當前路線是否通路(暢通|不暢通)-->完整路線
        intArrArrMaze[startPointX][startPointY] = 0;//試探迷宮回溯(測試點失敗走回)-->假定起點失敗

    return successFlag;
}

void AIUnitTest(int intArrArrMaze[10][10], int startPointX, int startPointY)
{
    int movePointX = startPointX;
    int movePointY = startPointY;
    while (endPointX != movePointX || endPointY != movePointY)
    {
        if (10 > movePointY + 1 && 3 == intArrArrMaze[movePointX][movePointY + 1])
        {
            intArrArrMaze[movePointX][movePointY + 1] = 0;
            operateMaze('d', movePointX, movePointY + 1);
        }
        if (10 > movePointX + 1 && 3 == intArrArrMaze[movePointX + 1][movePointY])
        {
            intArrArrMaze[movePointX + 1][movePointY] = 0;
            operateMaze('s', movePointX + 1, movePointY);
        }
        if (-1 < movePointY - 1 && 3 == intArrArrMaze[movePointX][movePointY - 1])
        {
            intArrArrMaze[movePointX][movePointY - 1] = 0;
            operateMaze('a', movePointX, movePointY - 1);
        }
        if (-1 < movePointX - 1 && 3 == intArrArrMaze[movePointX - 1][movePointY])
        {
            intArrArrMaze[movePointX - 1][movePointY] = 0;
            operateMaze('d', movePointX - 1, movePointY);
        }
    }
}

int main02(void)
{
    //showMaze(intArrArrMazeY);
    int successFlag = mazeAI(intArrArrMazeC, 0, 0);
    if (successFlag)
    {
        printf("可以走出! \n");
        intArrArrMazeY[0][0] = 1;
        showMaze(intArrArrMazeY);
    }
    else
    {
        printf("不可以走出! \n");
    }

    system("pause");
}

相關文章