您的位置:首页 > 职场人生

80道面试题及其解法(三)

2016-06-21 07:52 393 查看
现有LA与LB两个链表,已升序排列。将LA与LB合并后也按升序排列.

设指针pa与pb分别均指向LA与LB当前的结点,那么只需要每次比较当前的这两个节点,谁小就把谁加入到LC(新链表)中,然后小的这个链表的指针继续后移。这样最坏的复杂度也只是O(LENA+LENB),算法2的实现如下:

[cpp] view
plain copy

print?

//结点结构体定义

struct LNode{

int data;

LNode *next;

};

typedef LNode * LinkList;

void main()

{//函数声明

void creat_list(LinkList &L,int n);

void merge_list(LinkList &La,LinkList &Lb,LinkList &Lc);

void print_list(LinkList L);

//主函数开始

int n1,n2;

LinkList La,Lb,Lc;

printf("建立La链表开始:请先输入要建立的结点个数\n");

scanf("%d",&n1);

creat_list(La,n1);

printf("La链表信息如下:\n");

print_list(La);

printf("建立Lb链表开始:请先输入要建立的结点个数\n");

scanf("%d",&n2);

creat_list(Lb,n2);

printf("Lb链表信息如下:\n");

print_list(Lb);

printf("合并完两链表后如下:\n");

merge_list(La,Lb,Lc);

print_list(Lc);

}

void creat_list(LinkList &L,int n)

{ int i;

LinkList p,q;

L=(LinkList)malloc(sizeof(LNode));

L->next=NULL;//建立头结点

q=L;

for (i=1;i<=n;i++)

{p=(LinkList)malloc(sizeof(LNode));

printf("请输入第%d个节点的数据:",i);

scanf("%d",&p->data);

q->next=p;

q=q->next;//q后移

}

p->next=NULL;//最后一个节点是尾结点

}

void merge_list(LinkList &La,LinkList &Lb,LinkList &Lc)

{LinkList pa,pb,pc;

pa=La->next;pb=Lb->next;//a,b链表均指向自己的第一个结点

pc=Lc=La;//Lc链表自始至终就没有建立过,实际上LC就是借助指针去连接la和lb中的结点

while(pa&&pb)//不指向末尾

{

if (pa->data<=pb->data)//插入La

{pc->next=pa;

pc=pa;//pc后移

pa=pa->next;//La后移

}

else

{

pc->next=pb;

pc=pb;

pb=pb->next;

}

}//结束该循环后应该会剩下一个链表没合并完(假设俩个链表长度不一样)

pc->next=pa?pa:pb;//剩余

}

void print_list(LinkList L)

{

LinkList p=L->next;//指向第一个结点

while(p)

{

printf("%3d",p->data);

p=p->next;

}

printf("\n");

}

题目描述:

一个循环有序数组(如:3,4,5,6,7,8,9,0,1,2),不知道其最小值的位置,要查找任一数值的位置。要求算法时间复杂度为log2(n)。

问题分析:

我们可以把循环有序数组分为左右两部分(以mid
= (low+high)/ 2为界),由循环有序数组的特点知,左右两部分必有一部分是有序的,我们可以找出有序的这部分,然后看所查找元素是否在有序部分,若在,则直接对有序部分二分查找,若不在,对无序部分递归调用查找函数。

代码如下:

#include <iostream>

using namespace std;

int binarySearch(int a[],int low,int high,int value) //二分查找

{

if(low>high)

return -1;

int mid=(low+high)/2;

if(value==a[mid])

return mid;

else if(value>a[mid])

return binarySearch(a,mid+1,high,value);

else

return binarySearch(a,low,mid-1,value);

}

int Search(int a[],int low,int high,int value) //循环有序查找函数

{

int mid=(low+high)/2;

if(a[mid]>a[low]) //左有序

{

if(a[low]<=value && value<=a[mid] ) //说明value在左边,直接二分查找

{

return binarySearch(a,low,mid,value);

}

else //value在右边

{

return Search(a,mid+1,high,value);

}

}

else //右有序

{

if(a[mid]<=value && value<=a[high])

{

return binarySearch(a,mid,high,value);

}

else

{

return Search(a,low,mid-1,value);

}

}

}

int main()

{

int a[]={3,4,5,6,7,8,9,0,1,2};

cout<<Search(a,0,9,0)<<endl;

return 0;

}


二叉树学习之非递归遍历

二叉树递归遍历可谓是学过数据结构的同仁都能想一下就能写出来,但在应聘过程我们常常遇到的是写出一个二叉树非递归遍历函数,接着上篇文章写二叉树的非递归遍历,先难后易,一步一步的来.

先上代码:

[cpp] view
plain copy







#include "binarytree.h"

#include <stack>

#include <queue>

#ifndef RECU

#warning("RECU is not defined")

/**

*前序遍历(根左右)

*

*1、当前节点为非空,访问当前节点,压栈其右子节点,考虑其左子节点

*2、当前节点为NULL,出栈

*

*@param t to visit

*@param visit point to a func

*/

void pre_order(link t, void (*visit)(link))

{

std::stack<link> myStack;

while( t || !myStack.empty() ) {

if ( t ) {

visit(t);

myStack.push(t->rchild);

t = t->lchild;

} else {

t = myStack.top();

myStack.pop();

}

}

}

/**

*中序序遍历(左根右)

*

*1、当前节点为非空,在访问当前节点前要先访问其左子节点,

* 压栈当前节点,判断其左子结点,一直压栈左子节点

*2、当前节点为NULL,出栈访问,其左子结点比当前节点出栈访问早,

* 此时当前节点是其右节点的父节点的角色,考虑其右节点

*

*在遍历过程中角色转换很重要

*

*@param t to visit

*@param visit point to a func

*/

void in_order(link t, void (*visit)(link))

{

std::stack<link> myStack;

while( t || !myStack.empty() ) {

if ( t ) {

myStack.push(t);

t = t->lchild;

} else {

t = myStack.top();

myStack.pop();

visit(t);

t = t->rchild;

}

}

}

/**

*后序遍历(左右根)

*

*1、由于在访问当前树的根结点时,应先访问其左、右子树,因而先将根结点入栈,

* 接着将右子树也入栈,然后考虑左子树,重复这一过程直到某一左子树为空

*2、如果当前考虑的子树为空,

* 1.若栈顶不为空,说明第二栈顶对应的树的右子树未处理,

* 则弹出栈顶,下次循环处理,并将一空指针入栈以表示其另一子树已做处理;

* 2.若栈顶也为空树,说明第二栈顶对应的树的左右子树或者为空,或者均已做处理,

* 直接访问第二栈顶的结点,访问完结点后,若栈仍为非空,说明整棵树尚未遍历完,

* 则弹出栈顶,并入栈一空指针表示第二栈顶的子树之一已被处理。

*

*@param t to visit

*@param visit point to a func

*/

void post_order(link t, void (*visit)(link))

{

std::stack<link> myStack;

while( 1 ) {

if ( t ) {

myStack.push(t);

myStack.push(t->rchild);

t = t->lchild;

} else {

t = myStack.top();

myStack.pop();

if (!t) {

t = myStack.top();

myStack.pop();

visit(t);

if (myStack.empty())

break;

t = myStack.top();

myStack.pop();

}

myStack.push(NULL);

}

}

}

#endif

/**

*层遍历

*

*@param t to visit

*@param visit point to a func

*/

void level_order(link t, void (*visit)(link))

{

std::queue<link> myQueue;

if (t) {

myQueue.push(t);

while( !myQueue.empty() ) {

link tmp = myQueue.front();

myQueue.pop();

visit(tmp);

if (tmp->lchild != NULL)

myQueue.push(tmp->lchild);

if (tmp->rchild != NULL)

myQueue.push(tmp->rchild);

}

}

}


面试题整理-矩阵查找元素

需要在矩阵中查找元素。这个矩阵的排列如下:

每一行都是有序的。每一列都是有序的。

比如一个小矩阵。

10 30

20 80

现在,我们需要在一个这样N * M的矩阵中找到一个元素,并返回其位置。

思路

首先,这个题不太适合二分查找。因为并不能保证第二行的元素都一定比第一行的任意元素大。

所以应该是很难找到O(lgN)的算法。

每次都是取右上角的元素v与x(我们要查找的元素)进行比较较:

如果发现v > x,由于v所在列肯定比x大。所以v所在列可以舍弃。

如果发现v < x,由于v所在行肯定比x小。所以v所在行可能舍弃。

最后余下的,可能是一行,也可能是一列。总之可以利用二分查找来实现了。效率O(min(N, M)) + log(abs(M-N)).

解题

这里直接粘出代码。

[cpp] view
plain copy

int find(int **a, const int row, const int col, const int x, int *rpos, int *cpos) {

//右上角为起始点.

int from_row = 0, from_col = col - 1, v;

int b, e, mid;

*rpos = *cpos = -1;

while (from_row < row && from_col >= 0) {

v = a[from_row][from_col];

if (v == x) {

*rpos = from_row;

*cpos = from_col;

return 1;

}

from_row += x > v;

from_col -= v > x;

}

//最后剩下一行

if (from_row == (row - 1) && from_col != 0) {

b = 0, e = from_col + 1;

while (b < e) {

mid = b + ((e-b)>>1);

v = a[from_row][mid];

if (x == v) {

*rpos = from_row;

*cpos = mid;

return 1;

} else if (v > x) e = mid;

else b = mid + 1;

}

return 0;

}

//最后剩下一列

if (from_col == 0 && from_row != (row - 1)) {

b = from_row, e = row;

while (b < e) {

mid = b + ((e-b)>>1);

v = a[mid][0];

if (v == x) {

*rpos = mid;

*cpos = from_col;

return 1;

} else if (v > x) e = mid;

else b = mid + 1;

}

return 0;

}

//最后只剩下一个点

if (a[from_row][from_col] == x) {

*rpos = from_row;

*cpos = from_col;

return 1;

}

return 0;

}

这里写一个测试程序,如果有错,会输出Error。

大数整数乘法方法

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
char * bigmuilty(char*muiltied,int len1,char *muilty,int len2)//muiltied 为被乘数,len1为其长。muilty为乘数,len2为其长
{
int len;
int i=0;
int j=0;
int k=0;
int tmp_result=0;
int carry=0;
char* result;
len=len1+len2; //两个数相乘他们的最大长度为乘数与被乘数的长度和
result=(char*)calloc(len,1);//动态分配内存
for(i=0;i<len2;i++)//用乘数的每一位去乘以被乘数
{
for(j=0;j<len1;j++)
{
tmp_result=muilty[len2-i-1]*muiltied[len1-j-1];//得到零时结果
result[j+i]+=tmp_result;//如果以0为起始标号,被乘数和乘数下标分别从右往左依次增加,则结果存放的位置为j+i
}
for(k=0;k<=j+i-1;k++)//整理结果,使每位的值在0-9之间
{

if(result[k]>9)
{
carry=result[k]/10;
result[k]=result[k]%10;
result[k+1]+=carry;
}
}
}
return result;
}
int main()
{
int len1=0;
int len2=0;
int len;
int i=0;
int num='0';
char *result;
char muiltied[BUFSIZ];//被乘数存放位置
char muilty[BUFSIZ];
printf("entry muiltied : ");
scanf("%s",muiltied);
printf("\nentry muilty : ");
scanf("%s",muilty);
len1=strlen(muiltied);
len2=strlen(muilty);
len=len1+len2;
for(i=0;i<len1;i++)
{
muiltied[i]=muiltied[i]-num;
}
for(i=0;i<len2;i++)
{
muilty[i]=muilty[i]-num;
}
result=bigmuilty(muiltied,len1,muilty,len2);
i=len-2;
printf("\nresult : ");
if(result[len-1]>0)
{
printf("%c",result[len-1]+num);
}
while(i>=0)
{
printf("%c",result[i]+num);
i--;
}
printf("\n");
free(result);
return 0;
}

1.Copyright 1990 Software Development Systems, Inc.

2.Copyright 1986 - 1999 IAR Systems. All rights reserved

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  面试题 数据结构