線性表 查找

引入Key類。
Key類指要查找的數據中最關鍵最有標識性的部分,查找時通過key的比較,快速判斷出這個數據是否是要查找的數據。

#include<iostream>

using namespace std;

class Key
{
   int key; //數據中的關鍵部分,有辨識度
public:
   //static int comparisons; //比較次數
   Key (int x = 0);
   int the_key() const;
};

//int Key::comparisons = 0;

bool operator == (const Key &x,const Key &y); //"=="運算符重載
bool operator > (const Key &x,const Key &y); //">"運算符重載
bool operator < (const Key &x,const Key &y); //"<"運算符重載
bool operator >= (const Key &x,const Key &y); //">="運算符重載
bool operator <= (const Key &x,const Key &y); //"<="運算符重載
bool operator != (const Key &x,const Key &y); //"!="運算符重載

Key::Key(int x)
{
    key = x;
}

int Key::the_key() const
{
    return key;
}

bool operator == (const Key &x, const Key &y)
{
   //Key::comparisons++;
   return x.the_key() == y.the_key();
}

bool operator > (const Key &x, const Key &y)
{
   //Key::comparisons++;
   return x.the_key() > y.the_key();
}

bool operator < (const Key &x, const Key &y)
{
   //Key::comparisons++;
   return x.the_key() < y.the_key();
}

bool operator >= (const Key &x, const Key &y)
{
   //Key::comparisons++;
   return x.the_key() >= y.the_key();
}

bool operator <= (const Key &x, const Key &y)
{
   //Key::comparisons++;
   return x.the_key() <= y.the_key();
}

bool operator != (const Key &x, const Key &y)
{
   //Key::comparisons++;
   return x.the_key() != y.the_key();
}

一.順序查找(待查找的線性表已經是一個有序線性表)

  1. 查找有順序的線性表,從線性表的第一項開始,逐個進行比較。
#include "list.cpp"
#include "key.cpp"
typedef Key Record;

Error_code sequential_search(const List<Record> &the_list,const Key &target,int &position) //the_list引用提供的線性表,target引用數據中的關鍵部分,如果查找到將其位置賦給position
{
    int s = the_list.size(); //線性表大小
    for(position = 0;position < s;position++) //遍歷
    {
        Record data;
        the_list.retrieve(position,data); //將當前位置中存儲的數據賦給data
        if(data == target) return success; //如果data是要查找的數據,則查找成功,position正好是其位置
    }
    return not_present; //如果遍歷完仍未找到,說明該線性表中沒有這個數據
}

2.2. 查找有順序的線性表。加入一個哨兵,先將要查找的這一項插入表的末尾,這樣遍歷表時一定能找到一個正確位置,只需判斷所得的位置是否是最後一個位置即可。省去了判斷位置信息,不用擔心查找超界。

#include "list.cpp"
#include "key.cpp"
typedef Key Record;

Error_code sequential_search(List<Record> &the_list,const Key &target,int &position) //the_list引用提供的線性表,target引用數據中的關鍵部分,如果查找到將其位置賦給position
{
    Record data;
    int s = the_list.size(); //線性表大小

    the_list.insert(s,target); //將要查找的數據插入表的末尾
    for(position = 0;;position++) //遍歷
    {
        the_list.retrieve(position,data); //將當前位置中存儲的數據賦給data
        if(data == target) break;//如果data是要查找的數據,則跳出
    }
    the_list.remove(s,data); //刪除插入的數據
    if(position < s) return success; //如果position不是最後一項,則成功,position正好是其位置
    return not_present;//如果遍歷完仍未找到,說明該線性表中沒有這個數據
}

二.插半查找
引出 Orlist類.
將數據有順序的插入表中,要重載insert函數,覆蓋insert,replace函數。

#include "key.cpp"
#include "list.cpp"
typedef Key Record;

class Ordered_list:public List<Record>
{
public:
    Ordered_list(); //構造函數
    Error_code insert(const Record &data); //只傳入要插入的數據,由程序找合適的位置插入
    Error_code insert(int position, const Record &data); //傳入要插入的數據和指定位置,如果數據在該位置合適則插入,不合適則不插入,返回相應信息
    Error_code replace(int position, const Record &data);//傳入要替換的數據和指定位置,如果數據在該位置合適則替換,不合適則不替換,返回相應信息
};

Ordered_list::Ordered_list() //構造函數
{}

Error_code Ordered_list::insert(const Record &data) //以插入的數據爲參數傳入
{
    int s = size(); //獲取線性表的大小
    int position;
    for (position = 0; position < s; position++) //遍歷
    {
        Record list_data;
        retrieve(position, list_data); //返回當前位置的數據
        if (data <= list_data) break; //如果當前位置的數據大於等於要插入的數據,跳出
    }
    return List<Record>::insert(position, data); //將新的數據插入這個位置,這個位置原本的數據向後移一位
}

Error_code Ordered_list::insert(int position, const Record &data) //傳入要插入的數據和指定位置
{
    Record list_data;
    if (position > 0) //如果指定位置不是線性表頭
    {
        retrieve(position - 1, list_data); //返回前一個位置的數據
        if (data < list_data) //判斷,要插入的數據應該大於等於前一個位置的數據
            return fail; //如果要插入的數據小於前一個位置的數據,則不能插入
    }
    if (position < size()) //判斷指定位置是否合法
    {
        retrieve(position, list_data);//返回當前位置的數據
        if (data > list_data)//判斷,要插入的數據應該小於等於當位置的數據
            return fail;//如果要插入的數據大於當前位置的數據,則不能插入
    }
    return List<Record>::insert(position, data); //將新的數據插入這個位置,這個位置原本的數據向後移一位
}

Error_code Ordered_list::replace(int position, const Record &data) //傳入要替換的數據和指定位置
{
    Record list_data;
    if (position > 0) //如果指定位置不是線性表頭
    {
        retrieve(position - 1, list_data); //返回前一個位置的數據
        if (data < list_data) //判斷,要替換的數據應該大於等於前一個位置的數據
            return fail;//如果要替換的數據小於前一個位置的數據,則不能替換
    }
    if (position < size()-1) //判斷指定位置是否越界
    {
        retrieve(position+1, list_data);//返回下一個位置的數據
        if (data > list_data)//判斷,要替換的數據應該小於等於下一個位置的數據
            return fail;//如果要替換的數據小於下一個位置的數據,則不能替換
    }
    return List<Record>::replace(position, data); //替換這個位置的數據
}

1.將要查找的數據先與線性表的中間位置做比較,如果小於中間位置則說明要找的元素在後半部分,然後繼續折半查找後半部分;如果小於中間位置則說明要找的元素在前半部分,然後繼續折半查找前半部分。直到前後指針指向同一個元素,判斷是否是要查找的元素。

#include<iostream>
#include "ordlist.cpp"

using namespace std;

Error_code recursive_binary_2(const Ordered_list &the_list, const Key &target,int bottom, int top, int &position)//傳入排好序的鏈表,關鍵字,當前前指針的位置,當前後指針的位置,如果查到了將位置賦給position,
{
    Record data;
    if (bottom <= top)
    {
        int mid = (bottom + top) / 2; //找出中間座標
        the_list.retrieve(mid, data); //返回中間座標的值
        if (data == target)
        {
            position = mid;
            return success; //如果中間的值等於要查找的值,則成功
        }

        else if (data < target) //如果中間的值小於要查找的值,說明要查找的值在後半部分
            return recursive_binary_2(the_list, target, mid + 1, top, position); //遞歸,此時前指針移到中間位置的後一個位置
        else //如果中間的值大於要查找的值,說明要查找的值在前半部分
            return recursive_binary_2(the_list, target, bottom, mid - 1, position); //遞歸,後指針移到中間位置的前一個位置
    }
    else return not_present;
}

Error_code run_recursive_binary_2(const Ordered_list &the_list,const Key &target, int &position)
{
  return recursive_binary_2(the_list, target, 0, the_list.size() - 1, position); //給遞歸函數傳入初始值
}

2.要找到該數第一次出現的位置,我們只能在找出一個正確位置時先將它保存起來,這樣最後前後指針指向同一個元素時,如果是要查找的數據則一定是第一個。

#include<iostream>
#include "ordlist.cpp"

using namespace std;

Error_code recursive_binary_1(const Ordered_list &the_list, const Key &target,int bottom, int top, int &position)//傳入排好序的鏈表,關鍵字,如果查到了將位置賦給position
{
    Record data;
    if (bottom < top) //當前指針小於後指針
    {
        int mid = (bottom + top) / 2;//找出中間座標
        the_list.retrieve(mid, data);//返回中間座標的值
        if (data < target)   //如果中間的值小於要查找的值,說明要查找的值在後半部分
            return recursive_binary_1(the_list, target, mid + 1, top, position);//遞歸,前指針移到中間位置的後一個位置
        else       //如果中間的值大於要查找的值,說明要查找的值在前半部分
            return recursive_binary_1(the_list, target, bottom, mid, position); //遞歸,後指針移到中間位置
    }
    else if (top < bottom)
        return not_present;   //當前指針大於後指針時,說明沒有找到
    else {          //當前後指針指向同一個元素時
        position = bottom;//將這個位置賦給position
        the_list.retrieve(bottom, data);//取出這個位置的值
        if (data == target) return success;//如果這個位置的值等於要查找的值,則該位置一定是在這個表中第一次出現的位置
        else return not_present;//如果不是則說明表中沒有這個數據
    }
}

Error_code run_recursive_binary_1(const Ordered_list &the_list,const Key &target, int &position)
{
        return recursive_binary_1(the_list, target, 0, the_list.size() - 1, position); //將初始值傳給遞歸函數
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章