日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 运维知识 > linux >内容正文

linux

Linux C 算法——查找

發(fā)布時間:2023/12/9 linux 57 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Linux C 算法——查找 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

???? ?所謂“查找”記為在一個含有眾多的數據元素(或記錄)的查找表中找出某個“特定的”數據,即在給定信息集上尋找特定信息元素的過程。

????為了便于討論,必須給出這個“特定的”詞的確切含義。首先,引入一個“關鍵字”的概念;

??? 關鍵字(Key)?是數據元素(或記錄)中某個數據項的值,用它可以標識(識別)一個數據元素(或記錄);

?????查找(Serching)根據給定的某個值,在查找表中確定一個其關鍵字等于給定值的記錄或數據元素。若表中存在這樣的一個記錄,則稱查找成功,此時查找的結果為給出整個記錄的信息,或只是該記錄在查找表中的位置;若表中不存在關鍵字等于給定值的記錄,則稱查找不成功,此時查找的結果可給出一個“空”記錄或“空”指針。

???? 查找方法有順序查找、折半查找、分塊查找、Hash表查找等。查找算法的優(yōu)劣將影響到計算機的使用效率,應根據應用場合選擇相應的查找算法。評價一個算法的好壞,一是時間復雜度(T(n)),n 為問題的體積,此時為表長;二是空間復雜度(D(n));三是算法的結構等其他特性;

???? 對查找算法,主要分析其T(n)。查找過程是key的比較過程,時間主要耗費在各記錄的key與給定k值的比較上,比較次數越多,算法效率越差(即T(n)量級越高),故用“比較次數”刻畫算法的T(n)。另外,不能以查找某個記錄的時間來作為T(n),一般以“平均查找長度”來衡量 T(n)。

一、順序表的查找

??? ?所謂順序表(Sequential Table),是將表中記錄(R1 、R2。。。Rn)按其序號存儲于一維數組空間,其特點是相鄰記錄的物理位置也是相鄰的。

記錄Ri的類型描述如下:

[cpp]?view plaincopy
  • typedef?int?key_t;??
  • ??
  • typedef?struct?{??
  • ????key_t???key;?//記錄key值??
  • ????/*?value?...?*/??
  • }?record_t;??
  • <span?style="font-family:Arial;BACKGROUND-COLOR:?#ffffff"></span>??
  • 順序表類型描述如下:

    [cpp]?view plaincopy
  • #define?N?1024?????/*?max?length?of?list?=?n?*/??
  • ??
  • /*?{R0,?R1,?R2,?R3?...?Rn-1}?are?stored?in?from?data[1]?to?data[n],data[0]?is?reserved*/??
  • typedef?struct?{??
  • ????record_t????data[N?+?1];?//順序表空間;??
  • ????int?len;????//當前表長,標空時len?=?0;??
  • }?sqlist;??
  • 若說明: sqlist r,則(r.data[1],.......r.data[r.len])為記錄表(R1、R2 ...... Rn),Ri.key為r.data[i].key;

    算法思路

    ???設給定值為k,在表(R1、R2。。。Rn)中,從Rn開始,查找key = k的記錄。若存在一個記錄Ri (1<i<n)的key為k,則查找成功,返回記錄序號i;否則,查找失敗,返回0;

    算法描述:

    第一種:

    [cpp]?view plaincopy
  • int?sqsearch_1(sqlist?r,?key_t?k)??
  • {??
  • ????int?i;??
  • ??????
  • ????i?=?r.len;??
  • ????while?(i?>=?1?&&?r.data[i].key?!=?k)???
  • ????????i--;??
  • ??????
  • ????return?i;??
  • }??
  • 我們可以看出其比較次數最大是2 * len.

    第二種:

    [cpp]?view plaincopy
  • int?sqsearch_2(sqlist?r,?key_t?k)??
  • {??
  • ????int?i;??
  • ??????
  • ????r.data[0].key?=?k;?//k存入監(jiān)視哨??
  • ??????
  • ????i?=?r.len;??
  • ????while?(r.data[i].key?!=?k)//順序前往查找??
  • ????????i--;??
  • ??????????
  • ????return?i;??
  • }??
  • 這里比較次數最大為len.

    第二種算法中引用了“監(jiān)視哨”這個概念。它是放在data[0]位置的,這就我們前面講a[0]置空的原因;監(jiān)視哨在這里無需判斷是否越界,這樣比較次數就會少一半,這里現將k存入監(jiān)視哨,若對某個i 有r.data[i].key = k,則查找成功,返回i ;若i 從n 遞減到1 都無記錄的key為k,i 再減1?為 0 時,必有r.data[0].key = k ,說明查找失敗,返回i = 0;

    ?對于查找算法,ASL = O(n),則效率是很低的,意味著查找某記錄幾乎要掃描整個表,若表長len很大時,會令人無法忍受。

    二、折半查找算法

    ?折半查找算法即二分法,二分查找算法的前提是表必須是有序的

    算法思路:

    對給定值k,組不確定待查記錄所在區(qū)間,每次將搜索空間減少一半(折半),知道查找成功或失敗為止。

    設兩個指針(或游標)low 、high ,分別指向當前待查找表的上界(表頭)和下界(表尾)。對于表(R1、R2。。。Rn),初始時 low = 1、high = n,令:

    mid = [ (low + high) / 2 ]

    ?指向當前待查找表中間的那個記錄,下面舉例說明折半查找的過程:

    算法描述:

    [cpp]?view plaincopy
  • int?Binserch(sqlist?r,key_t?k)??
  • {??
  • ????int?low,high,mid;??
  • ????low?=?1;??
  • ????high?=?r.len;?//上下界初值??
  • ????while(low?<=?high)?//表空間存在時??
  • ????{??
  • ????????mid?=?(low?+?high)/2;?//求當前的mid??
  • ????????if(k?==?r.data[mid].key)??
  • ????????????return?mid;?//查找成功,返回mid??
  • ????????if(k?<?r.data[mid].key)??
  • ????????????high?=?mid?-1;?//調整上界,向左部查找??
  • ????????else??
  • ????????????low?=?mid?+?1;?//調整下界,向右部查找??
  • ????}??
  • ????return?0;?//low?>?high?查找失敗??
  • }??
  • 該例子中記錄表的查找過程可以用二叉樹來表示:

    ?

    我們可以看到:找到第6個元素僅需比較一次,找到第3和第9個元素需比較2次;找到第1、4、7和10個元素許比較3次;找到第2、5、8、11個元素需比較4次;

    在這個二叉樹中。樹中每個節(jié)點表示表中的一個記錄,節(jié)點中的值為該記錄在表中的位置,通常稱這個描述查找過程的二叉樹為判定書,從判定樹上可見,查找20的過程恰好是走了一條從根到節(jié)點4的路徑,和給定值進行比較的關鍵字個數為該路徑上的節(jié)點數或節(jié)點4在判定樹上的層次數。類似地,找到有序表中任意記錄的過程就是走了一條從根節(jié)點到該記錄相應的節(jié)點的路徑,和給定值進行比較的關鍵字個數恰為該節(jié)點在判定樹上的層次數。因此,折半查找法在查找成功時進行比較的關鍵字個數最多不超過樹的深度,而具有n個節(jié)點的判定書的深度為[log 2 n] + 1,所以,折半查找法在查找成功時和給定值進行比較的關鍵字個數之多為[log2 n] + 1。n為無窮時,大大優(yōu)于O(n);

    ?

    三、HASH查找

    ?????? HASH表,又稱散列表。在前面的討論的順序查找、折半查找中,其時間復雜度都在O(n)~O(log2 n)之間,不論ASL在哪個量級,都與記錄長度n有關。隨著n的擴大,算法的效率會越來越低。ASL 與n 有關是因為記錄在存儲器中的存放是隨機的,或者說記錄的key與記錄的存放地址無關,因而查找只能建立在key的“比較”基礎上。

    ?????? 理想的查找方法是:對給定的k,不經任何比較便能獲取所需的記錄,其查找的時間復雜度為常數級O(C)。這就要求在建立記錄表時,確定記錄的key與其存儲地址之間的關系f,即使key與記錄的存放地址H相對應。

    1、哈希查找(定義)

    ???? 哈希查找是給定鍵值key,通過公式f (key) 直接計算數據元素的存儲地址(哈希值)進行數據存儲(即建立哈希表)和進行數據查找的一種方法,該公式 f 稱為哈希函數。哈希查找的本質是怎么構造的表就怎么在表中查找,具有O(1)的查找效率。記為?H(key) = f (key);

    ?????不同的key 可能得到同一個Hash地址,即當 key1 != key2時,可能有 H(key1) = H(key2),此時稱key1和key2為同義詞。這種現象稱為“沖突”“碰撞”,因為一個單位只可存放一條記錄。一般,選取Hash函數只能做到使沖突盡可能少,卻不能完全避免。這就要求在出現沖突之后,尋求恰當的方法來解決沖突記錄的存放問題。

    ?

    2、哈希查找(步驟)

    建立哈希表操作步驟

    1)step1取數據元素的關鍵字key,計算其哈希函數值(地址)。若該地址對應的存儲空間還沒有被占用,則該元素存入;否則執(zhí)行step2解決沖突;

    2)step2根據選擇的沖突處理方法,計算關鍵字key的下一個存儲地址。若下一個存儲地址仍被占用,則繼續(xù)執(zhí)行step2,知道找到能用的存儲地址為止。

    哈希查找操作步驟:

    1)step1對給定key值,計算哈希地址H(key);若該地址上記錄不存在,則查找失敗,若記錄存在且key值匹配則查找成功;否則說明發(fā)生沖突,執(zhí)行step2解決沖突。

    2)step2 根據選擇的沖突處理方法,重復計算下一個存儲地址直到找到非空記錄并且key值相等才認為查找成功并結束,否則查找失敗。

    ?

    3、哈希函數構造方法

    這里主要介紹兩種構造方法:1)直接地址法 2)保留除數法

    4、解決沖突的方法

    這里主要介紹兩種解決沖突方法:1)開放地址法 2)鏈地址法

    ?5、下面介紹Hash查找的使用

    1、性探查法解決沖突時Hash表的查找及插入

    [cpp]?view plaincopy
  • #define?m?64?//設定表長m??
  • typedef?struct??
  • {??
  • ????keytype?key;?//記錄關鍵字??
  • ????.....??
  • }Hretype;??
  • ??
  • Hretype?HT[m];?//Hash表存儲空間??
  • ??
  • int?Lhashserch(Hretype?HT[m],keytype?k)?//線性探查法解決沖突時的查找??
  • {??
  • ????int?j,d,i?=?0;??
  • ????j?=?d?=?H(k);?//求Hash地址并賦給j和d??
  • ????while((i?<?m)&&(HT[j].key?!=?NULL)&&(HT[j].key?!=?k)??
  • ????{??
  • ????????i?++;???
  • ????????j?=?(d?+?i)?%?m;?//沖突時形成下一地址??
  • ????}??
  • ????if(i?==?m)??
  • ????????return?-1;?//表溢出時返回-1??
  • ????else??
  • ????????return(j);??
  • }?//HT[j.key?==?k,查找成功;H[j].key?==?NULL,查找失敗??
  • ??
  • void?LHinsert(Hretype?HT[m],Hretype?R)?//記錄R插入Hash表的算法??
  • {??
  • ????int?j?=?LHashserch(HT.R.key);?//查找R,確定其位置??
  • ????if((j?==?-1)?||?(HT[j].key?==?R.key))?//表溢出或記錄已存??
  • ????????ERROR();??
  • ????else??
  • ????????HT[j]?=?R;?//插入HT[j]單元??
  • }??
  • 2、鏈地址法解決沖突時Hash表的查找及插入

    [cpp]?view plaincopy
  • typedef?struct?node?//記錄對應節(jié)點??
  • {??
  • ????keytype?key;??
  • ????.....??
  • ????struct?node?*next;??
  • }Renode;??
  • ??
  • Renode?*LinkHserch(Renode?*HT[m],keytype?k)?//鏈地址法解決沖突時的查找??
  • {??
  • ????Renode?*p;??
  • ????int?d?=?H(k);?//求Hash地址d??
  • ????p?=?HT[d];?//取鏈表頭結點指針??
  • ????while(p?&&?(p->key?!=?k))??
  • ????????p?=?p->next;?//沖突時取下一同義詞節(jié)點??
  • ??????
  • ????return?p;??
  • }?//查找成功時p->key?==?k,否則p?=?^???
  • ??
  • void?LHinsert(Renode?HT[m],Renode?*S)?//將指針S所指記錄插入表HT的算法??
  • {??
  • ????int?d;??
  • ????Renode?*p;??
  • ????p?=?LinkHserch(HT,S->key);?//查找S節(jié)點??
  • ????if(p)??
  • ????????ERROR();?//記錄已存在??
  • ????else??
  • ????{??
  • ????????d?=H(S->key);??
  • ????????S->next?=?HT[d];??
  • ????????HT[d]?=?S;??
  • ????}??
  • } ?
  • 總結

    以上是生活随笔為你收集整理的Linux C 算法——查找的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。