查找

基礎知識

1.查找,常見的方法有順序查找二分(折半)查找哈希表查找二叉排序樹查找
2.二分查找代碼應能信手拈來,僅適用於事先已經排好序的順序表;哈希表和二叉排序樹查找的重點在於考查對應的數據結構而不是算法,哈希表的最主要優點是我們利用它能夠在O(1) 時間查找某一元素,是效率最高的查找方式,缺點是需要額外的空間實現哈希表;與二叉排序樹對應的數據結構是二叉搜索樹。
3.信手拈來的二分查找代碼程序:

int binarySearch(const vector<int> &v, int k) {
    if(v.empty()) return -1;   //沒有找到數字k
    int low=0;
    int high=v.size()-1;
    int middle;
    while(low<=high) {
        middle=(high+low)/2;
        if(v.at(middle)==k) return middle;
        else if(v.at(middle) < k) low=middle+1;
        else high=middle-1;     
    }
    return -1;   //沒有找到數字k
}

python版:

# coding = utf-8
import sys

if __name__ == "__main__":
  # 讀取第一行的n
  num_to_search = int(sys.stdin.readline().strip())
  input_list = list(map(int, sys.stdin.readline().strip().split()))
  if input_list:
    left=0
    right=len(input_list)-1
    while left<=right:
      mid=(left+right)//2
      if input_list[mid]==num_to_search:
        print(mid)
        break
      elif input_list[mid]<num_to_search:
        left = mid+1
      else:
        right = mid-1

4.時間複雜度:折半查找爲O(log2n) ,哈希表查找時間複雜度爲O(1)

應用:旋轉數組的最小數字

題目
把一個數組最開始的若干個元素搬到數組的末尾,我們稱之爲數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如數組{3, 4, 5, 1, 2}爲{1, 2, 3, 4, 5}的一個旋轉,該數組的最小值爲1。
思路
順序情況下直接輸出數組開頭元素。旋轉情況下,令index1指向開頭,index2指向結尾,不斷縮小數組大小,當只剩兩個數字時,index2即指向最小元素。
算法實現

int BinarySearchMin(vector<int> rotationArray) {
    if(rotationArray.emtpy()) return -1; 
    if(rotationArray.size() == 1) return rotationArray.at(0);
    int leftIndex=0;
    int rightIndex=rotationArray.size()-1;  
    if(rotationArray.at(rightIndex)>rotationArray.at(leftIndex)) return rotationArray.at(0);  //順序排列
    else {
        int midIndex=0;
        while(1){
            if(rightIndex-leftIndex==1) return return rotationArray.at(rightIndex);
            midIndex=(leftIndex+rightIndex)/2;
            if(rotationArray.at(midIndex)==rotationArray.at(leftIndex) && rotationArray.at(midIndex)==rotationArray.at(rightIndex)) {
                return SequentialSearchMin(rotationArray, leftIndex, rightIndex);  //遍歷子空間找最小值
            }
            if(rotationArray.at(midIndex)>=rotationArray.at(leftIndex)) leftIndex=midIndex;
            else rightIndex=midIndex;
        }
    }
}

測試用例

vector<int> v1 = {5,6,7,8,9,1,2,3,4};
vector<int> v2 = {4,6,7,8,9,1,2,3,4};
vector<int> v3 = {1,0,1,1,1};
vector<int> v4 = {1,2,3,4,5,6,7,8,9};
vector<int> v5 = {4};
vector<int> v6 = {};

應用:數字在排序數組中出現的次數

題目:統計一個數字在排序數組中出現的次數。例如輸入排序數組{1,2,3,3,3,3,4,5}和數字3,由於3在這個數組中出現了4次,因此輸出4。
思路
利用二分查找法分別找到第一個和最後一個3。
算法實現

int GetFirstK(const vector<int> &sortedArray, int k) {
    if(sortedArray.empty()) return -1;
    int low=0, high=sortedArray.size()-1, index=0; 
    while(low<=high){
        index=(low+high)/2;
        if(sortedArray.at(index)==k) {
            if(index==0) return index;
            else if(sortedArray.at(index-1)<k) return index;
            else if(sortedArray.at(index-1)==k) high=index-1;
        }
        else if(sortedArray.at(index)>k) high=index-1;
        else if(sortedArray.at(index)<k) low=index+1;   
    }
    return -1;
}

int GetLastK(const vector<int> &sortedArray, int k) {
    if(sortedArray.empty()) return -1;
    int low=0, high=sortedArray.size()-1, index=0; 
    while(low<=high){
        index=(low+high)/2;
        if(sortedArray.at(index)==k) {
            if(index==sortedArray.size()-1) return index;
            else if(sortedArray.at(index+1)>k) return index;
            else if(sortedArray.at(index+1)==k) low=index+1;
        }
        else if(sortedArray.at(index)>k) high=index-1;
        else if(sortedArray.at(index)<k) low=index+1;   
    }
    return -1;
}

測試用例

vector<int> v1={1,2,3,3,3,4,5};
    vector<int> v2={3,3,3,4,5};
    vector<int> v3={1,2,3,3,3};
    vector<int> v4={3};
    vector<int> v5={};
    cout << test(v1, 3) << endl;
    cout << test(v1, 4) << endl;
    cout << test(v1, 8) << endl;
    cout << test(v2, 3) << endl;
    cout << test(v3, 3) << endl;
    cout << test(v4, 3) << endl;
    cout << test(v5, 3) << endl;

應用:二叉搜索樹與雙向鏈表

題目:
輸入一個二叉搜索樹,將該二叉搜索樹轉換成一個排序的雙向鏈表。要求不能創建任何新的結點,只能調整樹中結點指針的指向。比如輸入圖4.12中左邊的二叉搜索樹,則輸出轉換後的排序雙向鏈表。
思路
二叉搜索樹中序遍歷時即可得到從小到大的順序排列。因此在中序遍歷中每次都記住上一個遍歷到的結點,然後更改指針指向即可。
注意*pLastNodeInList->m_pRight 這種寫法是錯誤的,因爲->* 優先級高。
算法實現

//
BinaryTreeNode* Convert(BinaryTreeNode *pRoot) {
    if(pRoot==NULL) return NULL;
    BinaryTreeNode* pLastNodeInList=NULL;  //pLastNodeInList指向雙向鏈表的尾結點
    ConvertCore(pRoot, &pLastNodeInList);
    BinaryTreeNode* pHeadOfList=pLastNodeInList;  //找到頭結點並返回
    while(pHeadOfList->m_pLeft != NULL) {
        pHeadOfList=pHeadOfList->m_pLeft;
    }
    return pHeadOfList;
}

void ConvertCore(BinaryTreeNode *pNode, BinaryTreeNode** pLastNodeInList) { //此處必須用指針的指針,因爲我們對*pLastNodeInList會有改變。
    if (NULL == pNode) return;
    ConvertCore(pNode->m_pLeft, pLastNodeInList);
    pNode->m_pLeft=*pLastNodeInList;  //程序中,令左結點指向前一個元素,右結點指向後一個元素
    if(*pLastNodeInList != NULL) (*pLastNodeInList)->m_pRight=pNode;
    *pLastNodeInList=pNode;
    ConvertCore(pNode->m_pRight, pLastNodeInList);   
}

測試用例

應用:第一個只出現一次的字符

題目: 在字符串中找出第一個只出現一次的字符。如輸入“abaccdeff”,則輸出'b'
分析: 查找。我們可以統計每個字符在該字符串中出現的次數,然後根據字符來查找它出現的次數,哈希表。定義哈希表的鍵值(Key)是字符,而值(Value)是該字符出現的次數。掃描字符串兩次完成任務。
算法實現

char FirstNotRepeatChar(char *pString) {
    if (!pString || !*pString) return '\0';  //空指針,或指針指向空字符
    int len = strlen(pString);
    vector<int> charMap(256, 0);
    for (int i = 0; i<len; i++) {
        charMap[pString[i]]++;
    }
    for (int i = 0; i<len; i++) {
        if (charMap[pString[i]] == 1) {
            return pString[i];
        }
    }
    return '\0';
}

測試用例

    char *a= "abaccdeff";
    a = NULL;
    a = "";
發佈了419 篇原創文章 · 獲贊 248 · 訪問量 125萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章