在面試的過程中,軟件主管爲了考察面試者的代碼水平,往往讓面試者手寫一段經典代碼,比如字符串拷貝函數strcpy()、冒泡排序、二叉樹的三種遍歷(先序、中序、後序)等。這就需要面試者在複習的過程中理清算法的原理、畫算法流程圖或者UML類圖、會寫僞代碼哪怕是中文也行。
下面介紹常見的幾種手寫代碼:
- 字符串拷貝函數strcpy()
//字符串複製,從src拷貝到dst
char* strcpy(char *dst, const char* src) {
assert(dst != NULL && src != NULL );
char *ret = dst;
while ((*dst++ = *src++) != '\0');
return ret;
}
- 冒泡排序
#include <stdlib.h>
#include <iostream>
using namespace std;
template<typename T>
//整數或浮點數皆可使用
void bubble_sort(T arr[], int len)
{
int i, j; T temp;
for (i = 0; i < len - 1; i++)
for (j = 0; j < len - 1 - i; j++)
if (arr[j] > arr[j + 1]) {
temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
int _tmain(int argc, _TCHAR* argv[])
{
int arr[] = { 61, 17, 29, 22, 34, 60, 72, 21, 50, 1, 62 };
int len = (int) sizeof(arr) / sizeof(*arr);
bubble_sort(arr, len);
for (int i = 0; i < len; i++)
cout << arr[i] << ' ';
cout << endl;
float arrf[] = { 17.5, 19.1, 0.6, 1.9, 10.5, 12.4, 3.8, 19.7, 1.5, 25.4, 28.6, 4.4, 23.8, 5.4 };
len = (int) sizeof(arrf) / sizeof(*arrf);
bubble_sort(arrf, len);
for (int i = 0; i < len; i++)
cout << arrf[i] << ' ';
cout << endl;
system("pause");
return 0;
}
- 二叉樹的先序、中序、後序遍歷,遞歸方式實現
typedef char ElemType;
typedef struct btnode
{
ElemType data;
struct btnode* lchild;
struct btnode* rchild;
}BTNode;
//先序遍歷(根-->左子樹 -->右子樹)
void PreOrder(BTNode *b)
{
if (b != NULL)
{
printf("%c ", b->data); //訪問根結點
PreOrder(b->lchild);
PreOrder(b->rchild);
}
}
//中序遍歷(左子樹 --> 根 -->右子樹)
void InOrder(BTNode *b)
{
if (b != NULL)
{
InOrder(b->lchild);
printf("%c ", b->data); //訪問根結點
InOrder(b->rchild);
}
}
//後序遍歷(左子樹 -->右子樹 --> 根)
void PostOrder(BTNode *b)
{
if (b != NULL)
{
InOrder(b->lchild);
InOrder(b->rchild);
printf("%c ", b->data); //訪問根結點
}
}
- 二叉樹的先序、中序、後序遍歷,非遞歸方式實現
//-------------- 非遞歸實現
//先序遍歷的非遞歸方法:由先序遍歷的過程可知,先訪問根結點,再訪問左子樹,最後訪問右子樹。
//因此,先將根結點進棧,在棧不空時循環: 出棧p,訪問*p結點,將其右孩子進棧,再將左孩子結點進棧。
//算法如下:
void PreOrder1(BTNode *b)
{
BTNode *St[100], *p;
int top = -1;
if (b != NULL)
{
top++; //根結點入棧
St[top] = b;
while (top > -1) //棧不爲空時循環
{
p = St[top]; //進棧並訪問該結點
top--;
printf("%c ", p->data);
if (p->rchild != NULL) //右孩子結點入棧
{
top++;
St[top] = p->rchild;
}
if (p->lchild != NULL) //左孩子結點入棧
{
top++;
St[top] = p->lchild;
}
}
printf("\n");
}
}
//中序遍歷的非遞歸方法:由中序遍歷的過程可知,採用一個棧保存需要返回的結點指針,先掃描(並非訪問)根結點的
//所有左結點並將它們一一入棧。然後,出棧一個結點,顯然該結點沒有左孩子結點或者右孩子結點已訪問過,則訪問它。
//接着,掃描該結點的右孩子結點,將其進棧,再掃描該右孩子結點的所有左結點並一一入棧,如此這樣,直到棧空爲止。
//算法如下:
void InOrder1(BTNode *b)
{
BTNode *St[100], *p;
int top = -1;
if (b != NULL)
{
p = b;
while (top > -1 || p != NULL)
{
while (p != NULL) //掃描*p的所有左結點併入棧
{
top++;
St[top] = p;
p = p->lchild;
}
if (top > -1)
{
p = St[top]; //出棧*p的結點
top--;
printf("%c ", p->data); //訪問之
p = p->rchild; //掃描*p的右孩子結點
}
}
printf("\n");
}
}
//後序遍歷的非遞歸方法:由後序遍歷的過程可知,採用一個棧保存需要返回的結點指針,先掃描根結點的
//所有左結點並將它們一一入棧,出棧一個結點*b即當前結點,然後掃描該結點的右孩子結點併入棧,再掃描
//該右孩子結點的所有左結點併入棧。當一個結點的左、右孩子結點均被訪問後再訪問該結點,如此這樣,
//直到棧空爲止。
// 其中的難點是如何判斷一個結點*b的右孩子已訪問過,爲此需要用p保存剛剛訪問過的結點(初值爲NULL),
//若b->rchild = p成立(在後序遍歷中,*b的右孩子結點一定剛好在*b之前訪問),說明*b的左、右子樹均已訪問,
//現在應訪問*b.
// 從上面的過程可知,棧中保存的是當前結點*b的所有祖先結點(均未訪問過)。
//算法如下:
void PostOrder1(BTNode *b)
{
BTNode *St[100], *p;
int flag, top = -1; //棧指針置初值
if (b != NULL)
{
do
{
while (b != NULL) //將*b的所有左結點進棧
{
top++;
St[top] = b;
b = b->lchild;
}
p = NULL; //p指向棧結點的前一個已訪問的結點
flag = 1; //設置b的訪問標記爲已訪問過
while (top != -1 && flag)
{
b = St[top]; //取出當前的棧頂元素
if (b->rchild == p) //右孩子不存在或後孩子已被訪問,則訪問*b
{
printf("%c ", b->data); //訪問*b結點
top--;
p = b; //p指向被訪問的結點
}
else
{
b = b->rchild; //b指向右孩子結點
flag = 0; //設置未被訪問的標記
}
}
} while (top != -1);
printf("\n");
}
}
- 求二叉樹的高度
//求二叉樹的高度
int BTNodeDepth(BTNode *b)
{
int lchildDep = 0, rchildDep = 0;
if (b == NULL)
return 0; //空樹的高度爲0
else{
lchildDep = BTNodeDepth(b->lchild); //左子樹的高度
rchildDep = BTNodeDepth(b->rchild); //右子樹的高度
return (lchildDep > rchildDep) ? (lchildDep + 1) : (rchildDep + 1); //取最大值再加1即可
}
}