亚洲一区爱区精品无码_无码熟妇人妻AV_日本免费一区二区三区最新_国产AV寂寞骚妇

《算法與數(shù)據(jù)結(jié)構(gòu)(實踐)》(數(shù)據(jù)結(jié)構(gòu)與算法導(dǎo)論)

時間:2022-06-16 12:37:08 綜合范文

  下面是范文網(wǎng)小編收集的《算法與數(shù)據(jù)結(jié)構(gòu)(實踐)》(數(shù)據(jù)結(jié)構(gòu)與算法導(dǎo)論),以供參考。

《算法與數(shù)據(jù)結(jié)構(gòu)(實踐)》(數(shù)據(jù)結(jié)構(gòu)與算法導(dǎo)論)

  遼寧省高等教育自學(xué)考試 軟件技術(shù)(應(yīng)用本科)專業(yè) 課程設(shè)計報告書 課程名稱 算法與數(shù)據(jù)結(jié)構(gòu)(實踐) 助學(xué)單位 信息技術(shù)學(xué)院 姓 名 劉佳旭 準考證號 0 成 績 二O一一年 四 月

  實驗 1 順序表的應(yīng)用 實訓(xùn)目的 1、掌握順序表的定義及操作的 C 語言實現(xiàn)方法 2、掌握相關(guān)操作的基本思想及其算法。

  實驗要求 1、線性表的基本概念和基本運算。

  2、順序表的存儲結(jié)構(gòu)和查找、插入、刪除等基本運算。

  3、單鏈表的存儲結(jié)構(gòu)以及單鏈表的建立、查找、插入刪除等操作。

  4、雙向鏈表的存儲結(jié)構(gòu)以及插入、刪除操作。

  5、靜態(tài)鏈表的存儲結(jié)構(gòu)和基本運算。

  6、利用線性表的基本運算解決復(fù)雜問題。

  實驗步聚 1. 創(chuàng)建和銷毀順序表存儲結(jié)構(gòu)。

  創(chuàng)建一個順序表 在順序表的指定位置插入一個元素; 在順序表的指定位置刪除一個元素; 將兩個有序順序表合并成一個新的有序順序表 -Linear sequence of storage, said table (structure) and realize the creation of a chronological table (data from the proposed) in the order of table elements to insert a specified location in order of table elements to delete a specified location will merge two tables in an orderly sequence into a new table in an orderly sequence 銷毀線性表 void Destroy_SeqList(PSeqList SeqListPoint) { /*銷毀順序表,入口參數(shù):為要銷毀的順序表指針地址,無返回值*/ if (SeqListPoint) //SeqListPoint=NULL; return ; } 設(shè)調(diào)用函數(shù)為主函數(shù),主函數(shù)對初始化函數(shù)和銷毀函數(shù)的調(diào)用如下:

  main() { PSeqList SeqListPoint; SeqListPoint =Init_SeqList( ); …… Destroy_SeqList (SeqListPoint); } } 2. 實現(xiàn)順序表的基本操作,如插入、刪除、查找和遍歷等。

  具體插入算法描述如下:

  InsertList(SeqList *L,int i,DataType x) {//在順序表 L 中第 i 個位置之前插入一個新結(jié)點 x if(i<1 || i>L->length+1) { printf("position error");return;} if(L->length>=ListSize)

  { printf("overflow");return;} for(j=L-length-1;j>=i-1;j--) L->data[j+1]=L->data[j]; //從最后一個結(jié)點開始逐一后移 L->data[i-1]=x; //插入新結(jié)點 x L->length++; //實際表長加 1 } 從上述的算法以及插入過程圖中可以看出,一般情況下,在第 i(1≤i≤n)個結(jié)點之前插入一個新結(jié)點時,需要進行 n-i+1 次移動。而該算法的執(zhí)行時間花在 for 循環(huán)的結(jié)點后移上,因此,該算法的時間復(fù)雜度不僅依賴于表的長度 n,而且還與結(jié)點的插入位置 i 有關(guān)。當 i=n+1 時,for 循環(huán)不執(zhí)行,無需移動結(jié)點,屬于最好情況,其時間復(fù)雜度為 O(1);當i=1,循環(huán)需要執(zhí)行 n 次,即需要移動表中所有結(jié)點,屬于最壞情況,算法時間復(fù)雜度為 O(n)。由于插入結(jié)點可在表的任何位置上進行,因此需要分析討論算法的平均移動次數(shù)。

  假設(shè) p i 是在第 i 個結(jié)點之前插入一個結(jié)點概率,則在長度為 n 的線性表中插入一個結(jié)點時所需要移動結(jié)點次數(shù)的期望值(平均次數(shù))為: 不失一般性,我們假定在線性表的任何位置上插入結(jié)點的機會是相等的,即是等概率的,則有:

  p 1 =p 2 = … = p n+1 =1/(n+1) 因此,在等概率情況下插入需要移動結(jié)點的平均次數(shù)為:

  恰好是表長的一半,當表長 n 較大時,該算法的效率是相當?shù)偷?。因?Eis(n)是取決于問題規(guī)模 n 的,它是線性階的,因此算法的平均時間復(fù)雜度是 O(n)。

  例如,假定一個有序表 A=(23,31,46,54,58,67,72,88),表長 n=8。當向其中插入 56時,此時的 i 等于 5,因此應(yīng)插入到第 i-1 個位置上,從而需要將第 i-1 個元素及之后的所有元素都向后移動一位,將第 i-1 個元素位置空出來,插入新元素。插入后的有序表為(23,31,46,54,56,58,67,72,88)。按上述移動次數(shù)的計算公式,可知本插入操作需要移動n-i+1=8-5+1=4 次。

  刪除結(jié)點運算的算法如下:

  DataType DeleteList(SeqList *L,int i) {//在順序表 L 中刪除第個結(jié)點,并返回刪除結(jié)點的值 if(i<1||i>L->length) { printf("position error");

  return Error; } x=L->data[i];//保存結(jié)點值 for(j=i;j<=L->length;j++) L->data[j-1]=L->data[j]; //結(jié)點前移 L->length--; //表長減 1 return x; } 該算法的時間復(fù)雜度分析與插入算法類似,刪除一個結(jié)點也需要移動結(jié)點,移動的次數(shù)取決于表長 n 和位置 i。當 i=1 時,則前移 n-1 次,當 i=n 時不需要移動,因此算法的時間復(fù)雜度為 O(n);由于算法中刪除第 i 個結(jié)點是將從第 i+1 至第 n 個結(jié)點依次向前移動一個位置,共需要移動 n-i 個結(jié)點。同插入類似,假設(shè)在順序表上刪除任何位置上結(jié)點的機會相等,q i 為刪除第 i 個結(jié)點的概率,則刪除一個結(jié)點的平均移動次數(shù)為:

  由此可以看出,在順序表上做刪除運算,平均移動結(jié)點次數(shù)約為表長的一半,因此,該算法的平均時間復(fù)雜度為 O(n)。

  7 7 、順 序 表 查 找 順序表是指線性表的順序存儲結(jié)構(gòu)。假定在本章的討論中,順序表采用一維數(shù)組來表示,其元素類型為 NodeType,它含有關(guān)鍵字 key 域和其它數(shù)據(jù)域 data,key 域的類型假定用標識符 KeyType(int)表示,具體表的類型定義如下:

  typedef struct { KeyType key; InfoType data; }NodeType; typedef NodeType SeqList[n+1]; //0 號單元用作哨兵 在順序表上的查找方法有多種,這里只介紹最常用的、最主要的兩種方法,即順序查找和二分查找。

  。

  順序查找(Sequential Search)又稱線性查找,它是一種最簡單和最基本的查找方法。其基本思想是:從表的一端開始,順序掃描線性表,依次把掃描到的記錄關(guān)鍵字與給定的值k 相比較;若某個記錄的關(guān)鍵字等于 k,則表明查找成功,返回該記錄所在的下標,若直到所有記錄都比較完,仍未找到關(guān)鍵字與 k 相等的記錄,則表明查找失敗,返回 0 值。因此,順序查找的算法描述如下:

  int SeqSearch(SeqList R,KeyType k,int n) {//從順序表 R 中順序查找記錄關(guān)鍵字為 k 的記錄,

  //查找成功返回其下標,否則返回 0;R[0]作為哨兵, //用 R[0].key==k 作為循環(huán)下界的終結(jié)條件。

  R[0].key=k; //設(shè)置哨兵 i=n; //從后向前掃描 while(R[i].key!=k) i--; return i; //返回其下標,若找不到,返回 0 } 由于這個算法省略了對下標越界的檢查,查找速度有了很大的提高,其哨兵也可設(shè)在高端,其算法留給讀者自己設(shè)計。盡管如此,順序查找的速度仍然是比較慢的,查找最多需要比較 n+1 次。若整個表 R[1..n]已掃描完,還未找到與 k 相等的記錄,則循環(huán)必定終止于R[0].key==k,返回值為 0,表示查找失敗,總共比較了 n+1 次;若循環(huán)終止于 i>0,則說明查找成功,此時,若 i=n,則比較次數(shù) C n =1;若 i=1,則比較次數(shù) C 1 =n;一般情況下 C i =n-i+1。因此,查找成功時平均查找長度為:

  即順序查找成功時的平均查找長度約為表長的一半(假定查找某個記錄是等概率)。如果查找成功和不成功機會相等,那么順序查找的平均查找長度:

  ((n+1)/2+(n+1))/2=3(n+1)/4 順序查找的優(yōu)點是簡單的,且對表的結(jié)構(gòu)無任何要求,無論是順序存儲還是鏈式存儲,無論是否有序,都同樣適用,缺點是效率低。

  順序表的簡單應(yīng)用 1、 有序表的合并 #include <iostream> using namespace std; int * init(int *x , int &n) { cout<<"輸入順序表的大小:"; cin>>n; x = (int*)malloc(sizeof(int) * n); cout<<"輸入"<<n<<"個數(shù)據(jù):"<<endl; for(int i = 0 ; i < n ; i++) cin>>x[i]; return x; } int * hebing(int *a , int *b , int na , int nb) { int * c = (int*)malloc(sizeof(int)*(na+nb)); int i = 0, j = 0 ,k = 0; while(i < na && j < nb)

  { if(a[i]<b[j]) { c[k] = a[i]; i++; } else { c[k] = b[j]; j++; } k++; } if( i == na) while(j < nb) c[k++] = b[j++]; else while(i < na) c[k++] = a[i++]; return c; } int main() { int *a , *b , *sum , na , nb; a = init(a,na); b = init(b,nb); sum = hebing(a,b,na,nb); for(int i = 0 ; i < na+nb ; i++) cout<<sum[i]<<" "; cout<<endl; return 0; } 二分法檢 索又稱折半檢索,二分法檢索的基本思想是設(shè)字典中的元素從小到大有序地存放在數(shù)組中,首先將給定值 key 與字典中間位置上元素的關(guān)鍵碼比較,如果相等,則檢索成功;否則,若 key 小,則在字典前半部分中繼續(xù)進行二分法檢索,若 key 大,則在字典后半部分中繼續(xù)進行二分法檢索。這樣,經(jīng)過一次比較就縮小一半的檢索區(qū)間,如此進行下去,直到檢索成功或檢索失敗。二分法檢索是一種效率較高的檢索方法,要求字典在順序表中按關(guān)鍵碼排序。

  實驗 2 鏈表的應(yīng)用 實驗?zāi)康? 1、熟悉 C 語言的上機環(huán)境,掌握 C 語言的基本結(jié)構(gòu)。

  2、會定義線性表的鏈式存儲結(jié)構(gòu)。

  3、熟悉對鏈表的一些基本操作和具體的函數(shù)定義。

  4、本章的主要任務(wù)是使用有關(guān)單鏈表的操作來實現(xiàn)通訊錄信息系統(tǒng)的管理。

  實驗要求 1. 創(chuàng)建和銷毀鏈表存儲結(jié)構(gòu)。

  2. 實現(xiàn)鏈表的基本操作,如插入、刪除、查找和遍歷等。

  3. 鏈表的簡單應(yīng)用,如約瑟夫環(huán)、集合求并、一元多項式相加等。

  實驗步驟 1. 創(chuàng)建和銷毀鏈表存儲結(jié)構(gòu)。

  創(chuàng)建鏈表 一般將鏈表中的每個數(shù)據(jù)對象稱為節(jié)點(Node)。創(chuàng)建鏈表的基本步驟如下: 第一步,創(chuàng)建第一個節(jié)點,并將此節(jié)點的內(nèi)存地址保存 第二步,創(chuàng)建第二個節(jié)點,將第二個節(jié)點的首地址保存在第一個節(jié)點的成員變量中。

  第三步,以此類推,創(chuàng)建第 n 個節(jié)點,并將此節(jié)點的地址存儲到第 n-1 節(jié)點的成員變量中。

  銷毀一個鏈表 在鏈表使用完畢后建議銷毀它,因為鏈表本身會占用內(nèi)存空間。如果一個系統(tǒng)中使用很多的鏈表,而使用完畢后又不及時地銷毀它,那么這些垃圾空間積累過多,最終可能導(dǎo)致內(nèi)存的泄漏甚至程序的崩潰。因此應(yīng)當養(yǎng)成及時銷毀不用的鏈表的習(xí)慣。

  函數(shù) destroyLinkList()的作用是銷毀一個鏈表 list,它包括以下步驟。

 ?。?)首先將*list 的內(nèi)容賦值給 p,這樣 p 也指向鏈表的第一個結(jié)點,成為了鏈表的表頭。

 ?。?)然后判斷只要 p 不為空(NULL),就將 p 指向的下一個結(jié)點的指針(地址)賦值給q,并應(yīng)用函數(shù) free()釋放掉 p 所指向的結(jié)點,p 再指向下一個結(jié)點。如此循環(huán),直到鏈表為空為止。

  (3)最后將*list 的內(nèi)容置為 NULL,這樣主函數(shù)中的鏈表 list 就為空了,防止了 list變?yōu)橐爸羔?。而且鏈表在?nèi)存中也被完全地釋放掉了。

  2. 實現(xiàn)鏈表的基本操作,如插入、刪除、查找和遍歷等。

  鏈表的插入 鏈表能夠方便地實現(xiàn)結(jié)點的插入和刪除操作,這也是鏈表結(jié)構(gòu)具有動態(tài)分配存儲空間的體現(xiàn),也是它優(yōu)于數(shù)組的地方之一。還是舉小朋友排隊的例子來說明鏈表的插入和刪除是怎樣實現(xiàn)的。在這個比喻里面,每一個小朋友相當于一個結(jié)點,一個小朋友的手拉著另一個小朋友的手,相當于一個結(jié)點的指針域指向下一個結(jié)點。假設(shè)現(xiàn)有一對按大小個排好隊的小朋友,又來一個小朋友需要加入該隊列。這時候,就需要從原來隊列里面的第一個小朋友開始,按照他們的身高找到新來小朋友應(yīng)該站的位置(前一個小朋友的身高比他矮,后一個小朋友的身高比他高)。然后,把這兩個小朋友的手分開,讓前一個小朋友的手該拉著新來小朋友的一只手,新來小朋友的另一只手拉著后一個小朋友的一只手。這樣,新來的小朋友就被插入到這個隊伍里面了,并且這個隊伍的小朋友還是按照身高順序排列的。特別地,如果新來

  小朋友最矮,他只需要站在隊伍的開頭,并且讓他的一只手拉著原來站在對頭的小朋友的手就行了。實際鏈表的插入操作也就可以類似地實現(xiàn)。

  鏈表的刪除 在鏈表中刪除一個節(jié)點,用圖 7 - 4 描述如下:

  [例 7-6] 創(chuàng)建一個學(xué)生學(xué)號及姓名的單鏈表,即節(jié)點包括學(xué)生學(xué)號、姓名及指向下一個節(jié)點的指針,鏈表按學(xué)生的學(xué)號排列。再從鍵盤輸入某一學(xué)生姓名,將其從鏈表中刪除。

  首先定義鏈表的結(jié)構(gòu):

  struct 從圖 7 - 4 中看到,從鏈表中刪除一個節(jié)點有三種情況,即刪除鏈表頭節(jié)點、刪除鏈表的中 間節(jié)點、刪除鏈表的尾節(jié)點。題目給出的是學(xué)生姓名,則應(yīng)在鏈表中從頭到尾依此查找各節(jié) 點,并與各節(jié)點的學(xué)生姓名比較,若相同,則查找成功,否則,找不到節(jié)點。由于刪除的節(jié) 點可能在鏈表的頭,會對鏈表的頭指針造成丟失,所以定義刪除節(jié)點的函數(shù)的返回值定義為 返回結(jié)構(gòu)體類型的指針。

  鏈表的遍歷和查找 我們可以用與 Length()函數(shù)類似的方法查找鏈表中的某一個結(jié)點。

  //給定鏈表的頭指針和待查結(jié)點數(shù)據(jù),返回查到的結(jié)點的指針 node* Find(node* head,int data) { node* current = head; while (current!=NULL) if(current->data == data) break; else current = current->next; return current; } Find()函數(shù)的功能是:輸入鏈表頭結(jié)點 head 和待查結(jié)點數(shù)據(jù) data,如果某一個結(jié)點的數(shù)據(jù)與 data 相等,則返回該結(jié)點的指針;如果查完每一個結(jié)點也沒有找到數(shù)據(jù)與 data相等的結(jié)點,則返回空指針。

  需要注意的是:Find 函數(shù)也可以寫成下面的形式。

  //給定鏈表的頭指針和待查結(jié)點數(shù)據(jù),返回查到的結(jié)點的指針 node* Find(node* head,int data) { node* current = head; while (current!=NULL&& current->data == data) current = current->next; return current; } 但把while的條件"current!=NULL&& current->data == data"寫成" current->data == data &&current!=NULL"的形式,則 Find 函數(shù)可能會出現(xiàn)運行錯誤。這是因為:如果鏈表的最后一個結(jié)點,仍然不是要找的結(jié)點,則到下一次循環(huán)時 current 為 NULL,再進行條件判

  斷時,前者 current!=NULL 為真,而不再作 current->data == data 的判斷,循環(huán)便結(jié)束;而后者在作 current->data == data 判斷時就會導(dǎo)致程序崩潰。

  3. 鏈表的簡單應(yīng)用,如約瑟夫環(huán)、集合求并、一元多項式相加等。

  鏈表的約瑟夫環(huán) #include <iostream> using namespace std; int mark[1005];// 數(shù)組來做表,方便快速高效 int cur;//表的 index. int main() { int n,m;//n 個人,數(shù)到第 m 個出列 scanf("%d%d",&n,&m);//輸入信息 int cnt ,on=n; cur = 1; int i; while(on--)//出列 n 次 { cnt=0; for(;cnt<m;++cur) { if(cur==n+1)cur=1; if(mark[cur])continue; ++cnt; } mark[cur-1]=1;//標記,出隊 printf("%d\n",cur-1); } return 0; }

  實驗 3 棧和隊列的應(yīng)用 實驗?zāi)康? 理解棧和隊列的工程原理,掌握棧和隊列在計算機程序設(shè)計中的應(yīng)用。

  實驗要求 1. 創(chuàng)建和銷毀棧和隊列的存儲結(jié)構(gòu),要求達到“熟練掌握”層次。

  2. 實現(xiàn)棧和隊列的基本操作,要求達到“熟練掌握”層次。

  3. 棧和隊列的簡單應(yīng)用,要求達到“基本掌握”層次。

  實驗步驟 1. 創(chuàng)建和銷毀棧和隊列的存儲結(jié)構(gòu)。

  //--------* Header File------------------------------------------------------------------------ #ifndef __STACK_H__ #define __STACK_H__ struct Node; typedef struct Node *PtrToNode; typedef PtrToNode Stack; int IsEmpty(Stack S); Stack CreateStack(void); void DisposeStack(Stack S); void MakeEmpty(Stack S); void Push(ElementType X, Stack S); ElementType Top(Stack S); void Pop(Stack S); #endif //---------------------------------------------------------------------------------------------- //--------* Implementation File-------------------------------------------------------------- //節(jié)點結(jié)構(gòu) struct Node { ElementType Element; PtrToNode Next; };

  //---------------------------------------------------------------------------------------------- //測試堆棧是否為空 int IsEmpty(Stack S) { return S->Next == NULL; } //---------------------------------------------------------------------------------------------- //創(chuàng)建一個空棧 Stack CreateStack(void) { Stack S; S = (Node *) malloc ( sizeof(struct Node) ); //分配一個節(jié)點的空間給棧 S if(S==NULL) exit(1); //分配失敗 S->Next = NULL; MakeEmpty(S); return S; } //---------------------------------------------------------------------------------------------- //將棧清空 void MakeEmpty(Stack S) { if(S == NULL) exit(1); else{ while(!IsEmpty(S)) Pop(S); } } //---------------------------------------------------------------------------------------------- //進棧 Push void Push(ElementType X, Stack S) { PtrToNode TmpCell;

  TmpCell = malloc(sizeof(struct Node)); if(TmpCell == NULL) exit(1); else { TmpCell->Element = X; TmpCell->Next = S->next; S->next = TmpCell; } } //----------------------------------------------------------------------------------------------

  實驗 4 樹和二叉樹的應(yīng)用 實驗?zāi)康? (1)熟練掌握樹的基本概念、二叉樹的基本操作及在鏈式存儲結(jié)構(gòu)上的實現(xiàn); (2)重點掌握二叉樹的生成、遍歷及求深度等算法; (3)掌握二叉樹的線索化及線索二叉樹的遍歷算法;掌握赫夫曼樹的含義及其應(yīng)用; (4)掌握運用遞歸方式描述算法及編寫遞歸 C 程序的方法,提高算法分析和程序設(shè)計能力。

  實驗要求 1. 創(chuàng)建和銷毀二叉樹的存儲結(jié)構(gòu)。

  2. 實現(xiàn)二叉樹的基本操作,如查找和遍歷等。

  3. 二叉樹的簡單應(yīng)用,如線索二叉樹、哈夫曼樹和表達式樹等。

  4. 樹轉(zhuǎn)化為二叉樹的存儲結(jié)構(gòu)的創(chuàng)建和銷毀。

  5. 樹與森林的遍歷算法。

  6. 樹的簡單應(yīng)用,如因特網(wǎng)查詢等。

  實驗步驟 1. 創(chuàng)建和銷毀二叉樹的存儲結(jié)構(gòu)。

  二叉樹的存儲結(jié)構(gòu)有多種,最常用的有兩種:是順序存儲結(jié)構(gòu)和鏈表存儲結(jié)構(gòu)。

  順序存儲結(jié)構(gòu) 二叉樹可以存放在一維數(shù)組之中,這是一種簡單的順序存儲結(jié)構(gòu)。請看如下語句:

  const int MAXSIZE 20 typedef char ElemType; ElemType bt[MAXSIZE]; 其中 Bt 就是一維數(shù)組(向量),用它來存儲一棵二叉樹,每個數(shù)組元素存儲樹的一個結(jié)點的數(shù)據(jù)信息。假設(shè)讓 bt[0] 閑置,讓 bt[1] 存放根結(jié)點信息。假設(shè)按照自上而下、自左至右的順序?qū)D (a) 的滿二叉樹存入一維數(shù)組 bt ,可以發(fā)現(xiàn)圖 (a) 中結(jié)的編號恰好與數(shù)組元素的下標號相對應(yīng),詳見 圖。根據(jù)二叉樹性質(zhì) 5 ,在 bt 數(shù)組中可以方便地由某結(jié)點 bt[i] 的下標 i ,找到它的雙親結(jié)點 bt[i/2] 或者它的左、右孩子結(jié)點 bt[2i] 、 bt[2i+1] 。例如 bt[2] 結(jié)點值為 B ,它的雙親結(jié)點是 bt[1] 值為 A ,左孩子結(jié)點是 bt[4] 值為 D ,右孩子結(jié)點是 bt[5] 值為 E 。

  鏈式存儲結(jié)構(gòu) 用于二叉樹存儲的鏈表結(jié)構(gòu),常見的有二叉鏈表和三叉鏈表。二叉鏈表的每個結(jié)點有一個數(shù)據(jù)域和兩個指針域,一個指針指向左孩子,另一個指針指向右孩子。

  2. 實現(xiàn)二叉樹的基本操作,如查找和遍歷等。

  二叉樹的一般操作,實現(xiàn)了下:

  主要練習(xí)了二叉樹的非遞歸遍歷,利用棧,和隊列來完成。

  代碼 #include "" #include "" #define MAXSIZE 20 //二叉樹結(jié)點的結(jié)構(gòu)體表示形式 typedef struct node{ char data; struct node* left,*right;

  }BTree; //棧的結(jié)構(gòu)體表示形式 typedef struct stackelem{ BTree* a[MAXSIZE]; int top; }Stack; //隊列的結(jié)構(gòu)體的表示形式 typedef struct queueelem{ BTree* b[MAXSIZE]; int front,rear;}Queue; //前序遍歷,遞歸的方法 void Preorder(BTree* bt){ if (NULL!=bt){ printf("%c ",bt->data); Preorder(bt->left); Preorder(bt->right);}} 3. 二叉樹的簡單應(yīng)用,如線索二叉樹、哈夫曼樹和表達式樹等。

  線索二叉樹:n 個結(jié)點的二叉鏈表中含有 n+1 個空指針域。利用二叉鏈表中的空指針域,存放指向結(jié)點在某種遍歷次序下的前趨和后繼結(jié)點的指針(這種附加的指針稱為"線索")。

  這種加上了線索的二叉鏈表稱為線索鏈表,相應(yīng)的二叉樹稱為線索二叉樹(Threaded BinaryTree)。根據(jù)線索性質(zhì)的不同,線索二叉樹可分為前序線索二叉樹、中序線索二叉樹和后序線索二叉樹三種。

  線索鏈表解決了二叉鏈表找左、右孩子困難的問題,出現(xiàn)了無法直接找到該結(jié)點在某種遍歷序列中的前趨和后繼結(jié)點的問題。

  哈夫曼樹:哈夫曼樹( Huffman )又稱最優(yōu)二叉樹,是一類帶權(quán)路徑長度最短的樹,有著廣泛的應(yīng)用。

  在討論哈夫曼樹之前首先需要弄清楚關(guān)于路徑和路徑長度的概念。樹中兩個結(jié)點之間的路徑由一個結(jié)點到另一結(jié)點的分支構(gòu)成。兩結(jié)點之間的路徑長度是路徑上分支的數(shù)目。樹的路徑長度是從根結(jié)點到每一個結(jié)點的路徑長度之和。

  4. 樹轉(zhuǎn)化為二叉樹的存儲結(jié)構(gòu)的創(chuàng)建和銷毀。

  完全二叉樹結(jié)點編號 在一棵 n 個結(jié)點的完全二叉樹中,從樹根起,自上層到下層,每層從左至右,給所有結(jié)點編號,能得到一個反映整個二叉樹結(jié)構(gòu)的線性序列。

  完全二叉樹的順序存儲 將完全二叉樹中所有結(jié)點按編號順序依次存儲在一個向量 bt[0..n]中。

  其中:

  bt[1..n]用來存儲結(jié)點 bt[0]不用或用來存儲結(jié)點數(shù)目。

  一般二叉樹的順序存儲 ① 將一般二叉樹添上一些 "虛結(jié)點",成為"完全二叉樹" ② 為了用結(jié)點在向量中的相對位置來表示結(jié)點之間的邏輯關(guān)系,按完全二叉樹形式給結(jié)點編號 ③ 將結(jié)點按編號存入向量對應(yīng)分量,其中"虛結(jié)點"用"∮"表示 5. 樹與森林的遍歷算法。

  前序遍歷樹 步驟:

  (1) 訪問根結(jié)點; (2) 按從左至右的次序前序遍歷根的各棵子樹。

  前序遍歷樹和前序遍歷與該樹相對應(yīng)的二叉樹具有相同的遍歷結(jié)果,即它們的前序遍歷是相同的。

  后序遍歷樹 步驟:

  (1) 按從左至右的次序后序遍歷根的各棵子樹; (2) 訪問根結(jié)點。

  后序遍歷樹和中序遍歷與該樹相對應(yīng)的二叉樹具有相同的遍歷結(jié)果。

  森林的遍歷 前序遍歷森林 步驟:

  (1) 訪問森林中第一棵樹的根結(jié)點; (2) 前序遍歷森林中第一棵樹的根結(jié)點的各子樹; (3) 前序遍歷森林中除第一棵樹外其余各樹所構(gòu)成的森林。

  前序遍歷森林和前序遍歷與該森林相對應(yīng)的二叉樹具有相同的遍歷結(jié)果。

  后序遍歷森林 步驟:

  (1) 后序遍歷森林中第一棵樹的根結(jié)點的各子樹; (2) 訪問森林中第一棵樹的根結(jié)點; (3) 后序遍歷森林中除第一棵樹外其余各樹所構(gòu)成的森林。

  后序遍歷森林和中序遍歷與該樹相對應(yīng)的二叉樹具有相同的遍歷結(jié)果。

  6. 樹的簡單應(yīng)用,如因特網(wǎng)查詢等。

  哈夫曼編碼(Huffman Encoding) 是最古老,以及最優(yōu)雅的數(shù)據(jù)壓縮方法之一。它是以最小冗余編碼為基礎(chǔ)的,即如果我們知道數(shù)據(jù)中的不同符號在數(shù)據(jù)中的出現(xiàn)頻率,我們就可以對它用一種占用空間最少的編碼方式進行編碼,這種方法是,對于最頻繁出現(xiàn)的符號制定最短長度的編碼,而對于較少出現(xiàn)的符號給較長長度的編碼。

  哈夫曼編碼可以對各種類型的數(shù)據(jù)進行壓縮,如應(yīng)用在 JPEG 圖像的算法很多領(lǐng)域. 在這里我們采用一個文本文件來演示哈夫曼編碼的.為了說明問題,這個文本文件是高度簡化,這樣程序會變得相對簡單,比較好理解. 1.文件內(nèi)容只會出現(xiàn) ASCII 字符.即字符集里的字符總數(shù)不超過 255. 2.用一串兩進制數(shù)比如 10,110,1110,0 來代表文件里字符.每個字符有一個獨立編碼.而且是一種特殊前綴的編碼,即任一個編碼都不是另外一個編碼的前綴. 3.統(tǒng)計文本文件中各個字符出現(xiàn)頻率,出現(xiàn)頻率最高的字符分配最短的號碼.

  實驗 5 圖 的應(yīng)用 實驗?zāi)康?(1)掌握線性結(jié)構(gòu)、樹形結(jié)構(gòu)和圖形結(jié)構(gòu)等基本數(shù)據(jù)結(jié)構(gòu)及算法的應(yīng)用; (2)掌握分治技術(shù)、貪心技術(shù)、回溯和分支限界等經(jīng)典算法設(shè)計技術(shù)應(yīng)用; (3)熟練掌握搜索算法和排序算法的應(yīng)用; (4)具備應(yīng)用算法與數(shù)據(jù)結(jié)構(gòu)開發(fā)簡單應(yīng)用軟件的能力。

  實驗要求 (1)圖的鄰接表和鄰接矩陣存儲結(jié)構(gòu)的創(chuàng)建和銷毀,要求達到“熟練掌握”層次。

  (2)實現(xiàn)圖的基本操作,要求達到“熟練掌握”層次。

  實驗步驟 1. 圖的鄰接表和鄰接矩陣存儲結(jié)構(gòu)的創(chuàng)建和銷毀。

  2.實現(xiàn)圖的基本操作,如查找和遍歷等。

  3.圖的應(yīng)用,如最小生成樹、單源最短路徑、拓撲排序等。

 ?。?). 圖的鄰接表和鄰接矩陣存儲結(jié)構(gòu)的創(chuàng)建和銷毀。

  ////////////////////////////////////////////////////////////////// //圖是通過文件建立的 //數(shù)據(jù)元素為 char 類型 //存儲結(jié)構(gòu)為鄰接表 //文件中第一行為圖的類型 //第二行為節(jié)點元素,以#結(jié)束 //下邊每一行為邊,和邊的權(quán)值 //下邊是文件的示例 /* 2 A B C D # A B 3 A C 4 B C 2 C D 4 D A 1 # # */ ////////////////////////////////////////////////////////////////// #include<iostream> #include<fstream> using namespace std; const int MaxNum= 20;

  const int Infinity=-1; typedef char VexType; typedef int ArcType; typedef struct QNode //定義隊列節(jié)點 { int data; QNode *next; }*LQueuePtr; struct LQueue //定義隊列結(jié)構(gòu)體 LQueuePtr front,rear;}; oid QueueInit(LQueue &Q) //隊列初始化 { =new QNode; ->next =0; = ;} void Enqueue(LQueue &Q,int e) { LQueuePtr s; s=new QNode; s->data =e; s->next =0; ->next =s; =s;} bool Dequeue(LQueue &Q,int &e) { LQueuePtr p; if( == ) return false; p= ; =p->next ; e= ->data ; delete p; return true;} pedef struct ArcNode //定義邊的結(jié)構(gòu)體 {int adjvex; ArcType info; ArcNode *nextarc; }*ArcPtr; struct VexNode //定義節(jié)點的結(jié)構(gòu)體 { VexType data; ArcPtr firstarc;}; struct ALGraph //定義圖的結(jié)構(gòu)體 { VexNode vexs[MaxNum+1];

  int kind,vexnum,arcnum;}; int LocateVex(ALGraph &G,VexType v) //在圖中找到某一個元素 { int i; for(i= ;i>0&& [i].data !=v;i--); return i;} void CreateGraph(ALGraph &G,char fn[]) //創(chuàng)建圖 { int i,j; VexType u,v; ArcPtr p; ifstream f; ArcType w; (fn); //打開文件失敗 if(!f) { =0; return; } //讀入圖的種類 f>> ; //先設(shè)置邊數(shù)為 0 =0; i=0; while(true) //向節(jié)點數(shù)組中添加節(jié)點 { f>>u; if("#"==u) break; i++; [i].data =u; [i].firstarc =0; } =i; while(true) //讀入各條邊 { f>>u>>v; if("#"==u||"#"==v) break; i=LocateVex(G,u); if(0==i) continue; j=LocateVex(G,v); if(0==j||j==i) continue; if(1==||3== )w=1; else f>>w; ++; p=new ArcNode; p->adjvex =j;

  p->info =w; p->nextarc =[i].firstarc ; [i].firstarc =p; if( <=2) continue; p=new ArcNode; p->adjvex =i; p->info =w; p->nextarc =[j].firstarc ; [j].firstarc =p; } (); } void OutputGraph(ALGraph &G) //輸出圖 void DFS(ALGraph &G,int i,bool visited[],void visit(VexType)) //圖的名稱,當前節(jié)點位置,標記數(shù)組,訪問函數(shù) { int j; ArcPtr p; //訪問當前節(jié)點 visit( [i].data ); //修改標記值 visited[i]=true; for(p=[i].firstarc ;p;p=p->nextarc ) { j=p->adjvex ; if(!visited[j]) //對下一個節(jié)點遞歸 DFS(G,j,visited,visit); }} void DFSTraverse(ALGraph &G,void visit(VexType)) { int i; bool visited[MaxNum+1]; for(i=1;i<= ;i++) //初始化標記數(shù)組 { visited[i]=false; }for(i=1;i<= ;i++) { if(!visited[i]) {DFS(G,i,visited,visit); } }} void BFSTraverse(ALGraph &G,void visit(VexType)) { //訪問節(jié)點 visit([v].data ); visited[v]=true; //將訪問的節(jié)點入隊 Enqueue(q,v); while(Dequeue(q,u)) //出隊并訪問 { for(p=[u].firstarc ;p;p=p->nextarc )

  { w=p->adjvex ; if(!visited[w]) {visit([w].data ); visited[w]=true; Enqueue(q,w); } }} }} int main() {ALGraph G; CreateGraph(G,""); cout<<"創(chuàng)建的圖為:"; OutputGraph(G); cout<<"深度優(yōu)先遍歷:"<<endl; DFSTraverse(G,visit); cout<<endl<<"廣度優(yōu)先遍歷"<<endl; BFSTraverse(G,visit); cout<<endl; return 0; } 2.實現(xiàn)圖的基本操作,如查找和遍歷等 #include<> #include<> struct graph {char tnode; char hnode; double quanzhi; }gr[100]; char node[50]=" "; double graphshu[50][50]; int mini(int t,int n) printf("用普里姆算法得出的結(jié)果是:\n"); printf("路徑為:"); int t2=0; for(k=0;k<n-1;k++) { int t1=mini(t2,n); sum=sum+graphshu[t2][t1]; for(int i=0;i<n;i++) graphshu[i][t2]=; graphshu[t2][t1]=; for(i=0;i<n;i++) graphshu[t1][i]=minval(graphshu[t2][i],graphshu[t1][i]); printf("(%c,%c)",node[t2],node[t1]); t2=t1; }printf("\n 最小生成樹的總耗費為:%f\n",sum); }void Kruscal(int k,int n)

  value=gr[0].quanzhi; for(i=1;i<k;i++)//tt 為最小權(quán)的下標 if(value>=gr[i].quanzhi) { tt=i; value=gr[i].quanzhi; }///////for(i=0;i<n;i++) { if(gr[tt].tnode==node[i]) ii=i; if(gr[tt].hnode==node[i]) jj=i; } if(nod[ii]==nod[jj]) {gr[tt].quanzhi=; continue; }else { if(nod[ii]>=nod[jj]) { for(i=0;i<n;i++) if(nod[i]==nod[ii]) nod[i]=nod[jj]; } else { for(i=0;i<n;i++) if(nod[i]==nod[jj]) nod[i]=nod[ii]; { cin>>gr[k].hnode; cin>>gr[k].quanzhi;} } int p,o=1; for(int j=0;j<k;j++)//n 為頂點數(shù) { for(int t=0;t<o;t++) if(gr[j].tnode!=node[t]) p=0; else { p=1; break; } if(p==0) { node[n]=gr[j].tnode; n++;o++; } } for(j=0;j<k;j++) {

  for(int t=0;t<o;t++) if(gr[j].hnode!=node[t]) p=0; else { p=1; break; } if(p==0) { node[n]=gr[j].hnode; n++;o++; } } for(int i=0;i<n;i++) for(int j=0;j<n;j++) graphshu[i][j]=; for(i=0;i<k;i++)//構(gòu)造數(shù)組 { for(int j=0;j<n;j++) if(gr[i].tnode==node[j]) { ii=j; break; } for(j=0;j<n;j++) if(gr[i].hnode==node[j]) { jj=j; break; } graphshu[ii][jj]=gr[i].quanzhi;} for(i=0;i<n;i++) for(int j=i;j<n;j++) graphshu[j][i]=graphshu[i][j]; // prim(k,n); char option; int x; for(x=1;x<=4;x++) { cout<<" 求給定網(wǎng)的最小生成樹"<<endl; cout<<" 1.普里姆(Prim)算法"<<endl; cout<<" 2.克魯斯卡爾(Kruskal)算法"<<endl; cout<<" 3.退出"<<endl; cout<<" 請選擇:"; cin>>option; switch (option) {

  case "1":Prim(n,k);break; case "2":Kruscal(n,k);break; case "3":return; } } } 輸入文件:

  如果該數(shù)字序列不是度序列,只需在第一行輸出“No!”; 如果該數(shù)字序列是一個度序列,首先在第一行輸出“Yes!”;然后在接下來的若干行里輸出一個符合該度序列的圖所有邊,每行一條邊。

  我們默認一個圖的頂點編號為 1 至 T,如果頂點 i 與 j 之間有一條邊,我們表示為“i j”。例如圖一就可以表示為:

  1 3 2 4 3 4 3 5 輸入樣例 1:

  5 3 2 1 1 1 輸出樣例 1:

  Yes! 1 3 2 4 3 4 3 5 輸入樣例 2:

  No! 說明:若連接結(jié)點之間的邊可以不止一條,這樣的圖稱為多重圖。一個結(jié)點如果有指向自己的邊,這條邊被稱為自環(huán)。無向簡單圖是指無自環(huán)的非多重圖。

  3.圖的應(yīng)用,如最小生成樹、單源最短路徑、拓撲排序等 /*已調(diào)試成功前半部分(yes/no)*/ #include<> #define NMAX 100 int main( ) { static a[NMAX][NMAX]; int top[NMAX]; int tops,i,temp,s=0,s1=0; scanf("%d",&tops); if(tops>NMAX) { fprintf(stderr,"too many vertax...\n"); return -1;

  } for(i=0;i<tops;++i) { scanf("%d",&temp); s+=top[i]=temp; if(temp%2)++s1; } if(s%2||s1%2) { printf("No!\n"); return 1; } printf("Yes!\n"); /* waiting...*/ return 0; }

  實驗 6 散列表 的應(yīng)用 實驗?zāi)康? (1)掌握散列查找的基本思想; (2)掌握閉散列表的構(gòu)造方法; (3)掌握線性探測處理沖突的方法; (4)掌握散列技術(shù)的查找性能。

  實驗要求 (1)了解 散列表存儲結(jié)構(gòu)的創(chuàng)建和銷毀。

  (2)了解實現(xiàn)散列表的基本操作,如插入、刪除和查找等。

  (3)解決散列沖突方法的應(yīng)用,如開放地址法和鏈地址法等。

  實驗步驟 散列表由固定數(shù)目的散列表元組成。散列表元或是空,或是包含有與某個關(guān)鍵字相關(guān)聯(lián)的數(shù)據(jù)。為了找到某個關(guān)鍵字值的數(shù)據(jù),就要通過散列函數(shù)作用于關(guān)鍵字值來計算出散列表元數(shù)。對于某一個給定關(guān)鍵字的值,散列函數(shù)總是產(chǎn)生出相同的散列表元數(shù)。

  沖突和重復(fù) 當散列表元的數(shù)目少于關(guān)鍵字值的數(shù)目時,兩個或者兩個以上的關(guān)鍵字值就有可能被散列到同一個散列表元上,這被稱作沖突。當發(fā)生沖突的時候,有兩種選擇,一種是擴展散列表元,使它可以含有多個表項;另一種是不能有多重散列表項。

  后種方法不是一個好的解決方案,這使我們構(gòu)造巨大的散列表以避免沖突。在大多數(shù)情況下,可以讓散列表元包含多個散列表項,而這些散列表項都是被散列到該散列表元的。

  散列表元可以是一個包含簡單表項的鏈表,空的散列表元含有一個空的鏈表,散列表元的新表項被附加到該散列表元的表項鏈表的尾部。

  Frank An(WindSor,Ontario,Canada)寫了一個簡單的算法,代碼如下:

  #include <iostream> #include <> using namespace std; enum HashKeyType { KEY_STRING, KEY_INT, KEY_LONG, KEY_USER1, KEY_USER2,

  KEY_USER3, KEY_USER4 }; //定義 1 struct HashEntryBase { HashEntryBase *Prev; HashEntryBase *Next; HashEntryBase(); virtual HashKeyType GetKeyType() const =0; virtual size_t Hash(size_t buckets) const =0; virtual int KeyEquals(const HashEntryBase *entry) const=0; }; //定義 2 struct HashEntryInt:public HashEntryBase { int Key; HashEntryInt(const int &k); HashEntryInt(const HashEntryInt &e); virtual HashKeyType GetKeyType() const; virtual size_t Hash(size_t buckets) const; virtual int KeyEquals(const HashEntryBase *entry) const; protected: HashEntryInt(); }; struct HashEntryIntDB:public HashEntryInt { int data; HashEntryIntDB(const int &k, const int &db):HashEntryInt(k) { data = db; } }; struct HashEntryStr:public HashEntryBase { string Key; HashEntryStr(const string &k); HashEntryStr(const HashEntryStr &e); virtual HashKeyType GetKeyType() const; virtual size_t Hash(size_t buckets) const;

  virtual int KeyEquals(const HashEntryBase *entry) const; protected: HashEntryStr(); }; struct HashEntryStrDB:public HashEntryStr { string data; HashEntryStrDB(const string &k, const string &db):HashEntryStr(k) { data = db; } }; //定義 3 class HashBucker; //定義 4 class HashTableBase { public: HashTableBase(size_t buckets); ~HashTableBase(); protected: bool AddEntry(HashEntryBase *newe); bool DelEntry(const HashEntryBase *dele); bool IsDupe(const HashEntryBase *dupe); const HashEntryBase * FindEntry(const HashEntryBase *find); virtual bool TravCallback(const HashEntryBase *e)const=0; bool Traverse(); size_t NoOfBuckets; HashBucker **Table; }; typedef bool(HashTableBase:: *HashTravFunc)(const HashEntryBase *e) const; //定義 3 class HashBucker { public: HashBucker(); ~HashBucker(); bool AddEntry(HashEntryBase *newe); bool DelEntry(const HashEntryBase *dele); bool IsDupe(const HashEntryBase *dupe);

  const HashEntryBase * FindEntry(const HashEntryBase *find); bool Traverse(const HashTableBase &table, HashTravFunc func); protected: HashEntryBase *First; }; //定義 5 typedef bool (*HashEnumFuncIntDB)(const int &k, const int &db); class HashTableIntDB: private HashTableBase { public: HashTableIntDB(size_t buckets):HashTableBase(buckets){}; bool Insert(const int &key, const int &db); bool Delete(const int &dele); int LookUp(const int &key); bool Enumerate(HashEnumFuncIntDB func); protected: virtual bool TravCallback(const HashEntryBase *e) const; HashEnumFuncIntDB EnumCallBack; }; typedef bool (*HashEnumFuncStrDB)(const string &k, const string &db); class HashTableStrDB: private HashTableBase { public: HashTableStrDB(size_t buckets):HashTableBase(buckets){}; bool Insert(const string &key, const string &db); bool Delete(const string &dele); string LookUp(const string &key); bool Enumerate(HashEnumFuncStrDB func); protected: virtual bool TravCallback(const HashEntryBase *e) const; HashEnumFuncStrDB EnumCallBack; }; //實現(xiàn) 1 inline HashEntryBase::HashEntryBase() { Prev=NULL; Next=NULL; } //實現(xiàn) 2 inline HashEntryInt::HashEntryInt()

  { } inline HashEntryInt::HashEntryInt(const int &k):Key(k) { } inline HashEntryInt::HashEntryInt(const HashEntryInt &e):Key() { } HashKeyType HashEntryInt::GetKeyType() const { return KEY_INT; } int HashEntryInt::KeyEquals(const HashEntryBase *entry) const { if(KEY_INT!=entry->GetKeyType()) printf("mismatched types.\n"); return (Key==((const HashEntryInt *)entry)->Key); } size_t HashEntryInt::Hash(size_t buckets) const { return size_t(Key%(unsigned long)buckets); } inline HashEntryStr::HashEntryStr() { } inline HashEntryStr::HashEntryStr(const string &k):Key(k) { } inline HashEntryStr::HashEntryStr(const HashEntryStr &e):Key() { } HashKeyType HashEntryStr::GetKeyType() const { return KEY_STRING; } int HashEntryStr::KeyEquals(const HashEntryBase *entry) const { if(KEY_STRING!=entry->GetKeyType()) printf("mismatched types.\n"); return (Key==((const HashEntryStr *)entry)->Key); } size_t HashEntryStr::Hash(size_t buckets) const

  驗 實驗 7 排序 的應(yīng)用 實驗?zāi)康? (1)掌握查找的不同方法,并能用高級語言實現(xiàn)查找算法。

 ?。?)熟練掌握順序表和有序表的順序查找和二分查找方法。

 ?。?)掌握排序的不同方法,并能用高級語言實現(xiàn)排序算法。

 ?。?)熟練掌握順序表的選擇排序、冒泡排序和直接插入排序算法的實現(xiàn) 實驗要求 (1)深化理解書本上的理論知識,將書本的知識變“活”(為已掌握,為已活用); (2)理論和實踐相結(jié)合,學(xué)會將相關(guān)的數(shù)據(jù)結(jié)構(gòu)和算法應(yīng)用于解決實際問題,培養(yǎng)數(shù)據(jù)結(jié)構(gòu)的應(yīng)用能力和軟件工程所需要的實踐能力。

  實驗步驟 輸入:一個包含 n 個正整數(shù)的文件,每個正整數(shù)小于 n,n 等于 10 的 7 次方(一千萬)。并且文件內(nèi)的正整數(shù)沒有重復(fù)和關(guān)聯(lián)數(shù)據(jù)。

  輸出: 輸入整數(shù)的升序排列 約束:

  限制在 1M 左右內(nèi)存,充足的磁盤空間 假設(shè)整數(shù)占 32 位,1M 內(nèi)存可以存儲大概 個整數(shù),第一個方法就是采用基于磁盤的合并 排序算法,第二個辦法就是將 0- 切割成 40 個區(qū)間,分 40 次掃描(/),每次讀入 個在一個區(qū)間的整數(shù),并在內(nèi)存中使用快速 排序。書中提出的第三個解決辦法是采用 bitmap(或者稱為 bit vector)來表示所有數(shù)據(jù)集合(注意到條件,數(shù)據(jù)沒有重復(fù)),這樣就可以一次性將數(shù)據(jù)讀入內(nèi)存,減少了掃描次數(shù)。算法的偽代碼如下:

  階段 1:初始化一個空集合 for i=[0,n) bit[i]=0; 階段 2:讀入數(shù)據(jù) i,并設(shè)置 bit[i]=1 for each i in the input file bit[i]=1; 階段 3:輸出 排序的結(jié)果 for i=[0,n) if bit[i]==1 write i on the output file 算法的時間復(fù)雜度為 O(N) #include <> #define WORD 32 #define SHIFT 5 #define MASK 0x1F #define N

  int bitmap[1 + N / WORD]; /* * 置位函數(shù)——用"|"操作符,i&MASK 相當于 mod 操作 * m mod n 運算,當 n = 2 的 X 次冪的時候,m mod n = m&(n-1) */ void set (int i) { bitmap[i>>SHIFT] |= (1 << (i&MASK)); } /* 清除位操作,用&~操作符 */ void clear (int i) { bitmap[i>>SHIFT] &= ~(1...

  數(shù)據(jù)結(jié)構(gòu)實驗

  數(shù)據(jù)結(jié)構(gòu)實習(xí)

  《數(shù)據(jù)結(jié)構(gòu)》實驗題

  數(shù)據(jù)結(jié)構(gòu)實習(xí)報告

  大數(shù)據(jù)應(yīng)用初探與實踐

《算法與數(shù)據(jù)結(jié)構(gòu)(實踐)》(數(shù)據(jù)結(jié)構(gòu)與算法導(dǎo)論)相關(guān)文章:


相關(guān)熱詞搜索:《算法與數(shù)據(jù)結(jié)構(gòu)(實踐)》