C 語言初學教材 - 第四章 線性搜尋

要在管理模式中查詢某個帳號是否已經註冊,也就是說要從陣列 userID 中搜尋某個作為帳號的字串是否存在。搜尋演算法在電腦科學中是很基本的概念,我們日常上網找資料的 Google 、 Yahoo 等搜尋引擎,就是應用搜尋技術相當純熟的公司。



搜尋的應用相當廣泛,例如在文件檔案中尋找相符的字句,在自己的硬碟中尋找過去有存檔的檔案,或是去某個網站查找資料,在搜尋引擎輸入關鍵字等等。搜尋太常用了,所以學習搜尋演算法也會是重要的課題。


可是搜尋演算法跟所用的資料結構關係密切,有排序的資料結構跟沒有排序的資料結構又有差別,就是說可以運用的搜尋演算法也有不同。有排序過的資料結構可以施用更有效率的二元搜尋演算法,然而目前我們的登入程式因為接受使用者新建帳號,所以採用的資料結構為沒有排序過的同質陣列,這無法採用二元搜尋演算法。


不過,有個更簡單的線性搜尋演算法,這是逐一從資料結構中比對資料項目使否與搜尋目標相同。其實,我們已經運用過了,就是在列印帳號名單的時候
for (j = 0; j < SIZE; j++) {
    if (userID[j][0] == '\0') {
        break;
    }
                                
    printf("%s - %s\n", userID[j], userCODE[j]);
}


如果字元陣列 userID[j] 的第一個字元為 '\0' ,就跳出迴圈,也就是說,程式一部分的任務是找到 '\0' ,這就是典型的線性搜尋的應用,所搜尋的是特定的字元 '\0' 。


我們現在要建置的是讓使用者輸入所要搜尋的帳號,因此程式稍有不同
// search 為查詢帳號指令
if (!strcmp(instruction, "search")) {
    state = N;
                            
    printf("\n請輸入要查找的帳號: ");
    scanf("%s", searchname);
                          
    for (j = 0; j < SIZE; j++) {
        if (!strcmp(userID[j], searchname)) {
            state = Y;
            break;
        }
    }
                            
    if (state == Y) {
        printf("\n帳號 %s 已經註冊,密碼是 %s\n", userID[j], userCODE[j]);
    }
    else if (state == N) {
        printf("\n還沒有 %s 的帳號註冊唷!\n", searchname);
    }
        continue; 
}


我們仍是以狀態進行控制,若管理員輸入 search 指令,就會先將狀態 state 設成 N ,當然,這要加入之前前面宣告的列舉常數之中
enum STATE {EXIT, RUN, WRONG_NAME, WRONG_CODE, Y, N};


然後要求管理員輸入要搜尋的帳號,接著便利用 for 迴圈在陣列中比對每一元素是否與目標值相同,若是有比對到相同的,狀態就會設成 Y 。


最後會依狀態顯示有找到或是沒找到的訊息。


管理模式的程式碼應調整如下
if (i == 0 && !strcmp(inputCode, userCODE[i])) {
    printf("\n\n您成功以管理員模式登入....\n");
    printf("將入帳號管理模式,請在提示符號 # 後輸入指令\n");
                    
    while (1) {
        printf("\n# ");
        scanf("%s", instruction);
                        
        // exit 為離開管理模式的指令
        if (!strcmp(instruction, "exit")) {
            break;
        }
                        
        // list 為列印使用者列表的指令
        if (!strcmp(instruction, "list")) {
            printf("\n以下為所有註冊使用者的帳號及密碼\n");
            printf("\n帳號 - 密碼\n");
            for (j = 0; j < SIZE; j++) {
                if (userID[j][0] == '\0') {
                    break;
                }
                                
                printf("%s - %s\n", userID[j], userCODE[j]);
            }
            continue;
        }
                        
        // search 為查詢帳號指令
        if (!strcmp(instruction, "search")) {
            state = N;
                            
            printf("\n請輸入要查找的帳號: ");
            scanf("%s", searchname);
                            
            for (j = 0;j < SIZE; j++) {
                if (!strcmp(userID[j], searchname)) {
                    state = Y;
                    break;
                }
            }
                            
            if (state == Y) {
                printf("\n帳號 %s 已經註冊,密碼是 %s\n", userID[j], userCODE[j]);
            }
            else if (state == N) {
                printf("\n還沒有 %s 的帳號註冊唷!\n", searchname);
            }
            continue; 
        }
                        
        // delete 為刪除帳號指令
        if (!strcmp(instruction, "delete")) {
            printf("\n您即將開啟刪除使用者帳號的功能....\n");
            continue;
        }
                        
        // sort 為排序指令
        if (!strcmp(instruction, "sort")) {
            printf("\n您即將開啟排序使用者帳號列表的功能....\n");
            continue;
        }
    } 
                    
    printf("\n\n您即將離開管理模式,請重新登入....\n\n");
    state = RUN;
    break;
}


完整的範例程式碼及編譯執行,請繼續參考


問題與討論
  1. 到網路上查有關二元搜尋演算法的說明,比較二元搜尋跟線性搜尋的優劣。
  2. 為什麼搜尋的部份要用狀態來控制?
  3. 還有哪些搜尋演算法呢?跟資料結構又有什麼關係呢?




沒有留言: