(說明:這些題就不是什麼花樣了,考的是你的基礎知識怎麼樣。再聰明而沒有實學的人都將會被這些題所淘汰。) 1.鏈表和數組的區別在哪裡? ANSWER 主要在基本概念上的理解。但是最好能考慮的全面一點,現在公司招人的競爭可能就在細節上產生,誰比較仔細,誰獲勝的機會就大。 1)數組在記憶體中是逐個存放的,也就是說倘若數組的第一個元素在地址A,則數組第二個元素就在地址A+1。而鏈表則不是,鏈表每個節點沒有相對固定的位置關係。某個節點在地址A其後的節點不一定是A+1,而在記憶體的其他空閑地區,呈現一種隨機的狀態。 2)數組一旦顯式的被申明後,其大小就固定了,不能動態進行擴充。而鏈表則可以,可以動態產生節點並且添加到已有的鏈表後面。 3) …… (大家一起想想) 2.編寫實現鏈表排序的一種演算法。說明為什麼你會選擇用這樣的方法? ANSWER 鏈表通常是插入排序,為什麼呢?在數組中插入排序實現時會大量的移動資料從而刪除位元置不正確的元素,這是順序表刪除操作的低效性。從數學的角度,順序表 (即數組)的刪除操作是O(n).鏈表就不同,由於其儲存位置的不固定性,其刪除固定位置的元素只需要O(1)的時間,所以整體效能上獲得比較大的提高。 3.編寫實現數組排序的一種演算法。說明為什麼你會選擇用這樣的方法? ANSWER 排序演算法非常成熟了,實際上排序是研究演算法的很有效例子。回答的時候盡量找一些比較有技術性的演算法,比如堆排序或者快速排序,如果寫冒泡什麼的,別人都會 寫,也就顯示不出你的優秀了。當然一定要注意給定的條件。不至於三個數讓你排序,你搞個快排,這就有點“宰牛刀殺雞”了。 4.請編寫能直接實現strstr()函數功能的代碼。 ANSWER 首先要知道strstr()這個函數是幹什麼的,自己去查查C語言的書,一般附錄後面會給出C語言標準庫的。這個題目實際上也是一類重要的演算法門類,叫做 “字串的模式比對”。它有很多的現成演算法,其中最簡單的要數樸素的匹配演算法,還有KMP,BM這些進階演算法,筆試估計是來不及寫的。下面給出樸素的匹配 演算法。 int stringMatching(char* pattern,char* text) { int pLen = strlen(pattern),tLen = strlen(text); for(int i = 0;i <= tLen - pLen;i++){ for(int j = 0; pattern[j] == text[i + j];j++); if(j == pLen) return i; } return -1; // Not found } 5.編寫反轉字串的程式,要求最佳化速度、最佳化空間。 ANSWER:迴圈當然是最簡單的。 void reverseString(char* str) { int n = strlen(str); for(int i = 0;i < n/2;i++) {int t = str[i];str[i] = str[n - i - 1];str[n - i - 1] = t;} } 6.在鏈表裡如何發現迴圈連結? ANSWER: 顯然只需要判斷是否存在回溯指標就行了。判斷,是否存在某個節點的後繼指向其前面位置的指標。具體實現的時候可以模仿DFS中的訪問標誌數組的方法,我們可以在struct node中設計該節點的一個訪問標誌位,設為visited 。每訪問一個節點就將其visited域置為1。這樣的話,一次遍曆下來,如果發現某個後續節點的visited域已經是1,那麼就可以判定其存在迴圈連結。具體的代碼就不寫了,太簡單了。 7.寫一個函數,檢查字元是否是整數,如果是,返回其整數值。(或者:怎樣只用4行代碼編寫出一個從字串到長整形的函數?) 分析 :簡單!掃描一遍,每次產生對應整數的最高位。一行也就搞定了! long convert(char* s_string,long s_integer) { for(int sLen = strlen(s_string), i = 0; i < sLen;s_integer += (s_string[i++] - '0')*pow(10,sLen - i - 1)); return s_integer; } 8.給出一個函數來輸出一個字串的所有排列。 ANSWER 簡單的回溯就可以實現了。當然排列的產生也有很多種演算法,去看看組合數學,還有逆序產生排列和一些不需要遞迴產生排列的方法。印象中Knuth的< TAOCP>第一卷裡面深入講了排列的產生。這些演算法的理解需要一定的數學功底,也需要一定的靈感,有興趣最好看看。 void permStr(char* str,int i) { if(i == strlen(str) - 1) printf("%s"n",str); else { for(int j = i;j < strlen(str);j++) { swap(&str[i],&str[j]); permStr(str,i + 1); swap(&str[i],&str[j]); } } } 9.給出一個函數來複製兩個字串A和B。字串A的後幾個位元組和字串B的前幾個位元組重疊。 anSwer 記住,這種題目往往就是考你對邊界的考慮情況。編程除了技術上的熟練以外,細心也是非常重要的。其實很多編程的大師可能並不是有特別的技術,往往就是他們 非常的耐心和細心,記住:編程是電腦科學中最基本的工作,它是最容易去掌握的,耐心點,細心點你一定能夠學好它。代碼看下面: char* myStrcpy(char* s,char* a,char* b,char n) { int aLen = strlen(a),bLen = strlen(b); if(n > aLen || n > bLen) return NULL; // Error for(int i = 0;i < aLen + bLen - n;i++) if(i < aLen - n) s[i] = a[i]; else s[i] = b[i - aLen + n]; s[i] = '"0'; return s; } 10.怎樣編寫一個程式,把一個有序整數數組放到二叉樹中? ANSWER :二叉搜尋樹的建樹方法。簡單的遞迴結構。實在不理解,乾脆記下來好了。關於樹的演算法設計一定要聯想到遞迴,因為樹本身就是遞迴的定義。這裡的遞迴應該是 理所當然的吧,不過,學會把遞迴改稱非遞迴也是一種必要的技術。畢竟,遞迴會造成棧溢出,關於系統底層的程式中不到非不得以最好不要用。但是對某些數學問 題,就一定要學會用遞迴去解決。 void insertNode(bTree** root,int val) { bTree* newNode = (bTree* ) malloc(sizeof(bTree)); newNode->data = val; newNode->lChild = NULL; newNode->rChild = NULL; if(!(*root)) *root = newNode; else if(newNode->data < (*root)->data) insertNode(&(*root)->lChild,val); else insertNode(&(*root)->rChild,val); } 11.怎樣從頂部開始逐層列印二叉樹結點資料?請編程。 ANSWER 二叉樹的層次遍曆沒什麼好說的,如果你不會還是早點把基礎複習一下。一個勁的往後學,才會發現原來最最重要的還是以前最基礎最簡單的。 typedef struct myBinaryTree { int data; struct myBinaryTree* lChild; struct myBinaryTree* rChild; } bTree; struct myQueen { bTree* que[QSIZE]; int front; int rear; } binQueue; // Global var void initQueue() { // front == real makes the queue empty binQueue.rear = QSIZE - 1; binQueue.front = binQueue.rear; for(int i = 0;i < QSIZE;i++) binQueue.que[i] = NULL; } int enQueue(bTree* newNode) { if(binQueue.front >= 1) binQueue.que[binQueue.front--] = newNode; else return 0; return 1; } bTree* deQueue() { int t; if(binQueue.front != binQueue.rear){ t = binQueue.rear; binQueue.rear--; return binQueue.que[t]; } else return NULL; } int levelTraversal(bTree** root) { initQueue(); bTree* lc = (bTree* ) malloc(sizeof(bTree)); bTree* rc = (bTree* ) malloc(sizeof(bTree)); bTree* p = (bTree* ) malloc(sizeof(bTree)); if((!lc) || (!rc) || (!p)){ printf("OVERFLOW"n"); exit(OVERFLOW); // Allocation Error } p = *root; if(!p) { printf("Empty Tree,build it first !"n"); return 0; } enQueue(p); // enqueue the root of the tree while (binQueue.front != binQueue.rear){ p = deQueue(); printf("%d ",p->data); lc = p->lChild; rc = p->rChild; if(lc != NULL) enQueue(lc); if(rc != NULL) enQueue(rc); } printf(""n"); return 1; } 12.怎樣把一個鏈表掉個順序(也就是反序,注意鏈表的邊界條件並考慮空鏈表)? ANSWER 前面說了,最基本的是最重要的。線性資料結構是學習資料結構的入門,一定要掌握好。微軟的題目還是跟國內的公司不一樣。國內的一上來就是些概念,跟考曆史一樣。 typedef struct listNode { struct listNode* link; int data; }node; node* getNode(node* newNode,int val) { if(!newNode) exit(OVERFLOW); newNode->link = NULL; newNode->data = val; return newNode; } /* Insert a new node after p */ int insertNode(node* prev,node* newNode) { if(!prev) return 0; newNode->link = prev->link; prev->link = newNode; return 1; } /* delete the node after the node prev */ int eraseNode(node*prev,node* p) { if(p == NULL) return 0; prev->link = p->link; free(p); return 1; } void buildList(node* head) { int value; node* newNode = (node* ) malloc(sizeof(node)); node* p = head; scanf("%d",&value); while(value != -1){ newNode = getNode(newNode,value); insertNode(p,newNode); p = p->link; newNode = (node* ) malloc(sizeof(node)); scanf("%d",&value); } } int reverseList(node* head) { node* p = head->link; node* q = p->link; if(p == NULL){ printf("The list is empty!"n"); return 0; } while(q != NULL){ node* newNode = (node* ) malloc(sizeof(node)); newNode = getNode(newNode,q->data); insertNode(head,newNode); eraseNode(p,q); q = (node* ) malloc(sizeof(node)); // Allocate again q = p->link; } p->link = NULL; return 1; } |