廈大數據結構2010年903 程序設計題 1.(15分)試用C語言編寫一個遍歷二叉查找樹的算法,要求遍歷過程剛好按照鍵值從大到小的次序進行. 解: 二叉查找樹(BST:Binary Search Tree)是一種特殊的二叉樹,它改善了二叉樹節點查找的效率。 二叉查找樹有如下性質: (1)若左子樹不空,則左子樹上全部節點的值均小於它的根節點的值 (2)若右子樹不空,則右子樹上全部節點的值均大於它的根節點的值 (3)左、右子樹也分別爲二叉排序樹 (4)沒有鍵值相等的節點 所以,有如下數據結構定義: typedef struct BSTreeNode{ //數據域 ElemType data; //遞歸定義 左右子樹 struct BSTreeNode *left; struct BSTreeNode *right; }BSTree; void BSTreeSearch(tree *t){ if (t == NULL) { return ; } else { BSTreeSearch(t->rchild); visit(t); BSTreeSearch(t->lchild); } } 2.(15分)設L是一個帶頭結點的非遞減有序單鏈表的表頭指針. 試設計一個算法,將元素e插入到鏈表L中的合適地方,使得該鏈表還是非遞減有序. 解: 單鏈表的數據結構聲明: typedef struct LinkList{ ElemType data; LinkList *next; }*L; void insert(list &L, element a){ L = L -> next; while (a > L -> data && a <= L-> next -> data){ L = L -> next; } Node* newNode; newNode -> data = a; newNode -> next = L -> next; L -> next = newNode; } //插入新結點 void insert(LinkList * newNode){ LinkList *temp = L; while (temp -> next != NULL) { if (temp -> next -> num > newNode -> num){ break; } temp = temp -> next; } newNode -> next = temp -> next; temp -> next = newNode; } //打印列表 void output() { LinkList *p; p = L -> next; while (p != NULL){ printf("%d\t", p->num); } printf("\n"); } int main(){ L = new LinkList; L -> next = NULL; L -> num = MAXN; int n; while(1){ scanf("%d",&n); LinkList *now; now = new LinkList; now -> next = NULL; insert(now); output(); } return 0; } //--------------------------------------------------------------// 廈大數據結構2011年903 程序設計題 1.(15分)有一個帶頭結點的單鏈表L = {a1,b1a2,b2,...,an,bn}. 請設計一個函數將其拆分爲兩個帶頭結點的單鏈表A和B,正序鏈表A= {a1,a2,..,an}, 逆序鏈表B={bn,bn-1,...,b2,b1}.要求鏈表A使用鏈表L的頭結點. [注]函數的頭部爲void split(LinkList *&L, LinkList *&A, LinkList *&B) 解: typedef struct LinkList{ ElemType data; LinkList *next; }*L; //頭插法拆分鏈表 void split(LinkList *&L, LinkList *&A, LinkList *&B){ LinkList *p,*q; A = p = q = L; while (p -> next != NULL){ q = p -> next -> next; p -> next -> next = q -> next; //彈出最近的B,插入到B鏈表的頭結點後 q -> next = B -> next; B -> next = q; p = p -> next -> next; } } LinkList splitLinkList(LinkList &A){ LinkList B = (LinkList) malloc (sizeof(NODE)); B -> next = NULL; //p爲工做指針 LinkList p = A -> next,q; LinkList ra = A; while (p){ ra -> next = p; ra = p; //q是爲了防止斷鏈 q = p -> next; p -> next = B -> next; B -> next = p; p = q; } ra -> next = NULL; return B; } 2.(15分)假設用單鏈表方式來存儲整數序列,以下形式: [0| ] -> [3| ] -> [0| ] -> [3| ] -> [1| ] -> [3| ^] 請編寫一個遞歸算法,對這樣的鏈表進行處理,重複結點(值相同的結點). 僅保留排在最前面的一個,最後返回新鏈表的首地址. 例如,如有上述鏈表,則處理後的新鏈表以下: [0| ] -> [3| ] -> [1|^] 解: 算法思想:從單鏈表的第一個結點開始,對每一個結點進行檢查: 檢查鏈表中該結點的全部後繼結點,只要有值和該結點的值相同,則刪除值; 而後檢查下一個結點,知道全部的結點都被檢查完. typedef struct LNode { ElemType data; struct LNode *next; } //遞歸刪除以L爲頭結點的單鏈表中全部值相同的結點 void RecDelete_Node(LNode *L){ if (L == NULL) return; LNode *pre = L; LNode *cur = pre -> next; while (cur!=NULL){ if (cur->data == L->data){ pre -> next = cur -> next; free(cur); cur = pre -> next; } else { pre = cur; cur = cur -> next; } } L = L -> next; RecDelete_Node(L); } //非遞歸算法 void IterDeleteNode(LNode *L){ //刪除以單鏈表L中全部值相同的結點 LNode *p = L,*q,*ptr; //刪除以單鏈表L中全部值相同的結點 while (p != NULL) { q = p, ptr = p -> next; //檢測結點p的全部後繼結點ptr while (ptr != NULL) { if (ptr -> data = p -> data) { q -> next = ptr -> next; free(ptr); ptr = q -> next; } else { q = ptr; ptr = ptr -> next; } } p = p -> next; } } //--------------------------------------------------------------// 廈大數據結構2012年903 程序設計題 1.(15分)在一個遞增有序的線性表中,有數值相同的元素存在,若存儲方式爲單鏈表, 請設計算法去掉數值相同的元素,使表中再也不有重複的元素. 例如,下列線性表(7,10,10,21,30,42,42,42,61,70) 將變成(7,10,21,30,42,51,70) 請分析所設計算法的時間複雜度. 解: 數據結構定義: typedef struct LinkList{ ElemType data; LinkList *next; }*L; LinkList DeleteSameElem(LinkList &L){ //表按照增序排列(從小到大),去掉相同元素,使得表中再也不有相同元素 LNode *pre = L; LNode *p = L -> next; LNode *s = L; while (p != NULL) { if (pre -> data == p -> data){ //防止斷鏈 s = p; pre -> next = p -> next; p = p -> next; //釋放相同元素結點空間 free(s); } else { //若不相等時,同時後移 p = p -> next; pre = pre -> next; } } return L; } (2006年期末考卷A卷) 2.(15分)試設計算法在O(n)時間內將數組A[0..n-1]劃分爲左右兩個部分,使得左邊的元素均爲 奇數,右邊的元素均爲偶數,要求所使用的輔助空間大小爲O(1). 解: 主要思路: (1)設置兩個指針i和j,其中i=1,j = n; (2)當i < j時,做以下循環: i不斷自增 從左往右 找到第一個偶數 j不斷自減 從左往右 找到第一個奇數 A[i]和A[j],不斷交換 (3)算法結束 void Adjust (int a[], int n){ int i = 0; int j = n -1; while (a[i]%2 != 0){ i++ } while (a[j]%j == 0){ j++ } if (i < j){ int temp = a[i]; a[i] = a[j]; a[j] = temp; } } int main(){ int a[6] = {1,3,2,4,8,6}; Adjust(a,6); for (int i = 0; i < 6; i++){ printf("%5d\n",a[i]); } return 0; } //--------------------------------------------------------------// 廈大數據結構2013年903 程序設計題 1.(15分)請利用兩個隊列Q1和Q2來模擬一個棧. 已知隊列的三個運算,定義以下: bool EnQueue(Queue &Q, int e):插入一個元素e入隊列 bool DeQueue(Queue &Q, int &e):刪除一個元素e出隊列 bool QueueEmpty(Queue Q):判隊列爲空 假設數據結構Queue已定義,棧Stack的數據結構定義以下: typedef struct{ Queue Q1; Queue Q2; }Stack; 請利用隊列的運算來實現該棧的三個運算: Push(ST,x):元素x入ST棧 Pop(ST,x):ST棧頂元素出棧,賦給變量x StackEmpty(ST):判ST棧是否爲空 void Push(Stack ST,element x) { element e; //把Q1中全部元素壓入Q2 while (!QueueEmpty(ST.Q1)){ //刪除Q1中準備被壓入Q2的元素 DeQueue(ST.Q1,e); //把Q2取出來的元素壓入Q1隊列 EnQueue(ST.Q2,e); } EnQueue(ST.Q1,x); while (!QueueEmpty(ST.Q2)) { //刪除Q2中準備被壓入Q1的元素 DeQueue(ST.Q2,e); //把Q2取出來的元素壓入Q1隊列 EnQueue(ST.Q1,e); } } //用隊列模擬出棧比入棧容易的多,因爲剛剛壓入的元素在隊列Q1的頭, //只要彈出即爲彈棧操做 void Pop(Stack ST,element){ element e; //隊列爲空,沒法完成彈棧 if (QueueEmpty(ST.Q1)) return; DeQueue(ST.Q1,e); } bool StackEmpty(Stack ST){ if (QueueEmpy()){ return true; } else { false; } } 2.(15分)下面小題與二叉樹的遍歷有關係: (1)已知二叉樹的後序序列"abcdefg",同時已知二叉樹的中序序列"acbgdef", 是否能惟一肯定一棵二叉樹?若是能,請畫出二叉樹 (2)假設post[ps..ps+n-1]爲二叉樹的後序序列,ins[is..is+n-1]爲二叉樹的中序序列. 設計算法由兩個序列構造二叉樹的二叉鏈表. 解:(1)圖略 (2)程序以下: BTNode *CreateBT(char *post, char *in, char *n) { BTNode *s; char *p; if (n <= 0) return NULL; s = (BTNode*)malloc(sizeof(NTNode)); s -> data = *(post+(n-1)); for (p = in; p < in+n; p++) { if (*p == *(post+(n-1))) break; k = p - in; s -> lchild = CreateBT(post,in,k); s -> rchild = CreateBT(post,p+1,n-k-1); } return s; } Status CreateBiTree(BiTree &T) { scanf(&ch); if (ch == NULL) T = NULL; else { if ((!T=(BiTree*)malloc(sizeof(BiTNode)))) exit(OVERFLOW); T -> data = ch; CreateBiTree(T -> lchild); CreateBiTree(T -> rchild); } return OK; } //--------------------------------------------------------------// 廈大數據結構2014年903 程序設計題 1.(15分)判斷兩個非遞減有序的線性表中是否存在相同(關鍵字值相等)的元素, 若是相同的元素,返回第一個相同的元素在第一個有序表中的位置,不然返回0. 請合適的物理存儲結構,用C語言給出該物理存儲結構的類型定義,並在其上編寫算法. typedef struct{ ElemType *elem; int length; int listsize; }List; int judge(List A, List B){ for (int i = 0; i < A.length; i++){ int flag = 0; for (int j = 0; j < B.length; j++){ if (A.elem[i] == B.elem[j]){ flag = i; break; } } } return flag; } 2.(15分)編寫函數判斷一棵二叉樹是否不含有度爲1的結點,若任何結點的度都不爲1, 則返回TRUE,不然返回FALSE,結點與二叉樹的數據結構以下: typedef struct BiNode(){ TElemType Data; //左右孩子指針 struct BiTNode *lchild,*rchild; } BiTNode,*BiTree; 程序設計以下: int search(BiTNode *tree){ if ((tree -> lchild == NULL && tree -> rchild != NULL) || (tree -> rchild == NULL && tree -> lchild != NULL)){ return false; } else { //判斷是葉子節點,什麼都不作 if (tree -> lchild == NULL && tree -> rchild == NULL){ } else { search(tree -> lchild); search(tree -> rchild); } //可以到達這一步說明全部節點就沒有單個孩子,則返回true; return true; } } //本題採用遞歸思想,非遞歸的思想也能實現.可是遞歸可以反應算法素養,每每能獲得更高的分. //--------------------------------------------------------------// 廈大數據結構2015年903 程序設計題 1.(15分)在n個元素中,找到第k大的元素,用C語言寫出數據結構,設計算法實現上述要求, 並分析時間複雜性,最好是平均時間複雜度爲O(n). 解: 思路:尋找n個數中最大的k個數,本質上就是尋找最大的k個數中最小的那個,也就是第k大的數. 可使用二分搜索的策略來尋n個數中的第k大的數. 用數組a[max]做爲存儲數據結構,在數組a中查找. 算法代碼以下: //快速排序的劃分函數 int partition(int a[], int l, int r){ int i,j,x,temp; i = l; j = r + 1; x = a[l]; //將>=x的元素換到左邊區域 //將<=x的元素換到右邊區域 while (1) { while (a[++i] > x); while (a[--j] < x); if (i >= j) break; temp = a[i]; a[i] = a[j]; a[j] = temp; } a[l] = a[j]; a[j] = x; return j; } //隨機劃分函數 int random_partition(int a[], int l,int r){ //生產隨機數 int i = l + rand()%(r-l+1); a[i] = a[l]; a[l] = temp; //調用劃分函數 return partition(a,l,r); } //線性尋找第 k 大的數 int random_select(int a[],int l,int r,int k){ int i,j; if (l == r) //遞歸結束{ return a[l]; } i = random_partition(a,l,r);//劃分 j = i-l+1; if(k == j) //遞歸結束,找到第 K 大的數 return a[i]; if(k < j) { //遞歸調用,在前面部分查找第k大的數 return random_select(a,l,i-1,k); } else //遞歸調用,在後面部分查找第k大的數 return random_select(a,i+1,r,k-j); } 2.(15分)請用C語言寫出二叉樹的數據結構,並設計判斷兩個二叉樹是否相同(包括二叉樹的結構 以及每一個對應的結點的數據域data均相同)的算法. 解: 二叉樹的數據結構: typedef struct bitree{ int data; bitree *lchild; bitree *rchild; }bitree; int judgebitree(bitree *bt1, bitree *bt2){ if (bt1 == 0 && bt2 == 0) return (1); else if (bt1 == 0 || bt2 == 0 || bt1 -> data != bt2 -> data){ return (0); } else { return (judgebitree(bt1 -> lchild, bt2 -> lchild) && judgebitree(bt1 -> rchild, bt2 -> rchild)) } } //--------------------------------------------------------------// (排列組合算法) 廈大數據結構2016年903 程序設計題 設計算法以求解從集合{1…n}中選取k(k<=n)個元素的全部組合。例如,從集合{1…4}中選取2個元素的全部組合的輸出結果爲:1 2,1 3,1 4,2 3, 2 4,3 4。 1.(15分)設計算法以求解從集合{1,n}中來選取k(k<=n)個元素的全部組合. 例如{1,4}中選取2個元素的全部組合的輸出結構爲1 2,1 3,1 4,2 3,2 4,3 4, 輸入:4 2 輸出: 1 2 1 3 1 4 2 3 2 4 3 4 函數的頭部爲Void print_combination(int n, int k) void print_combination(int n, int k){ a[k] = {1,2,3,4}; if (n == k){ for (int i = 0; i < k; i++){ printf("%d\n",a[i]); printf("%d\n"); } } else { for (int j = n; j < k; j++){ print_combination(n+1,k); swap(&a[j], &a[index]); } } } void swap(int *p1, int *p2){ int t = *p1; *p1 = *p2; *p2 = t; } 2.(15分)在徹底二叉樹上,給定結點x,按照層次序打印結點x的全部子孫,請給出結點的數據結構和 算法,而且分析算法的時間複雜度. //--------------------------------------------------------------// 廈大數據結構2017年903 程序設計題 1.(15分)寫出一個結點具備M個指針會的M對的數據結構,並設計一個遞歸算法計算M叉樹的深度. 其中M爲常量,設只有一個根節點的樹深度爲1,空樹深度爲0,計算嘗試函數的輸入爲節點指針和 M值. 2.一個僅由0,1,2三種數構成的數組A共有N個元素,亂序排列在一塊兒. 0,1,2的數量均大於0,但具體的個數未知,請設計一種時間複雜度爲O(n)的算法, 將數組排成以下形狀,0,01,12,2(即前面都是0,中間都是1,後面都是2) //--------------------------------------------------------------// 廈大數據結構2018年903 程序設計題 1.(15分)描述下面這個算法,並用非遞歸形式來實現這個算法. Status time (int &sum){ int x; Scanf("%d\n",&x); if (x == 0){ return sum = 1; } else { time(sum); sum *= x; printf("%d\n",&sum); } return OK; } 2.寫二叉樹數據結構,葉子浮點型. 二叉樹中序遍歷3+4*5,設計算法實現這一計算過程.