2023年程序员面试精选_第1页
2023年程序员面试精选_第2页
2023年程序员面试精选_第3页
2023年程序员面试精选_第4页
2023年程序员面试精选_第5页
已阅读5页,还剩12页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

程序员经典1双向链表的查找节点。ﻫ考点:双向链表的操作

出现频率:★★★★ﻫ解析:

使用right指针遍历,直至找到数据为data的节点,假如找到节点,返回节点,否则返回NULL。

1

//查找节点,成功则返回满足条件的节点指针,否则返回NULLﻫ2

DbNode

*FindNode(DbNode

*head,

int

data)

//参数1是链表的表头节点

3

{

//参数2是要查找的节点,其数据为dataﻫ4

DbNode

*pnode

head;ﻫ5

6

if

(head

==

NULL)

//链表为空时返回NULL

7

{

8

return

NULL;

9

}

10

11

/*找到数据或者到达链表末尾退出while循环*/

12

while

(pnode->right

!=

NULL

&&

pnode->data

!=

data)ﻫ13

{ﻫ14

pnode

=

pnode->right;

//使用right指针遍历

15

}ﻫ16

17

//没有找到数据为data的节点,返回NULL

18

if

(pnode->right

==

NULL)ﻫ19

{ﻫ20

return

NULL;ﻫ21

}

22ﻫ23

return

pnode;ﻫ24

}2考点:模板的特化的理解

出现频率:★★★ﻫ解析:

模板的特化(template

specialization)分为两类:函数模板的特化和类模板的特化。ﻫ(1)函数模板的特化:当函数模板需要对某些类型进行特别解决,称为函数模板的特化。例如:ﻫ1

bool

IsEqual(T

t1,

T

t2)ﻫ2

{ﻫ3

return

t1

==

t2;ﻫ4

}

5ﻫ6

int

main()ﻫ7

{ﻫ8

char

str1[]

=

"Hello";

char

str2[]

=

"Hello";ﻫ10

cout

<<

IsEqual(1,

1)

<<

endl;ﻫ11

cout

<<

IsEqual(str1,

str2)

<<

endl;

//输出0ﻫ12

return

0;ﻫ13

}ﻫ代码11行比较字符串是否相等。由于对于传入的参数是char

*类型的,max函数模板只是简朴的比较了传入参数的值,即两个指针是否相等,因此这里打印0。显然,这与我们的初衷不符。因此,max函数模板需要对char

*类型进行特别解决,即特化:ﻫ1

template

<>

2

bool

IsEqual(char*

t1,

char*

t2)

//函数模板特化ﻫ3

{ﻫ4

return

strcmp(t1,

t2)

==

0;ﻫ5

}ﻫ这样,当IsEqual函数的参数类型为char*

时,就会调用IsEqual特化的版本,而不会再由函数模板实例化。

(2)类模板的特化:与函数模板类似,当类模板内需要对某些类型进行特别解决时,使用类模板的特化。例如:

template

2

class

compareﻫ3

{

4

public:

5

bool

IsEqual(T

t1,

T

t2)ﻫ6

{ﻫ7

return

t1

==

t2;

}ﻫ9

};

10ﻫ11

int

main()ﻫ12

{ﻫ13

char

str1[]

=

"Hello";ﻫ14

char

str2[]

"Hello";ﻫ15

compare

c1;ﻫ16

compare

c2;

17

cout

<<

c1.IsEqual(1,

1)

<<

endl;

//比较两个int类型的参数ﻫ18

cout

<<

c2.IsEqual(str1,

str2)

<<

endl;

//比较两个char

*类型的参数ﻫ19

return

0;ﻫ20

}这里代码18行也是调用模板类compare的IsEqual进行两个字符串比较,显然这里存在的问题和上面函数模板中的同样,我们需要比较两个字符串的内容,而不是仅仅比较两个字符指针。因此,需要使用类模板的特化:ﻫ1

template<>

2

class

compare

//特化(char*)ﻫ3

{ﻫ4

public:

5

bool

IsEqual(char*

t1,

char*

t2)

6

{ﻫ7

return

strcmp(t1,

t2)

==

0;

//使用strcmp比较字符串ﻫ8

}ﻫ9

};

注意:进行类模板的特化时,需要特化所有的成员变量及成员函数。3考点:双向链表的操作

出现频率:★★★★ﻫ解析:ﻫ与测长的方法同样,使用right指针进行遍历。ﻫ1

//打印整个链表

2

void

PrintList(DbNode

*head)

//参数为链表的表头节点ﻫ3

{

4

DbNode

*pnode

=

NULL;ﻫ5ﻫ6

if

(head

==

NULL)

//head为NULL表达链表空ﻫ7

return;

9

}ﻫ10

pnode=

head;ﻫ11

while

(pnode

!=

NULL)ﻫ12

{ﻫ13

printf("%d

",

pnode->data);ﻫ14

pnode

=

pnode->right;

//使用right指针遍历

15

}

16

printf("");

17

}4考点:类模板的实例化的理解

出现频率:★★★★

1

templateﻫ2

class

Array

{ﻫ3

};

5

void

foo(

)

6

{ﻫ7

Array

arr1;ﻫ8

Array

arr4,

arr5;

9

Array

arr2,

arr3;ﻫ10

Array

arr6;

11

…ﻫ12

}ﻫHow

many

instances

of

the

template

class

Array

will

get

instantiated

inside

the

function

foo()ﻫA

B

6

C

4

D

解析:

模板类(template

class)的实例个数是由类型参数的种类决定的。代码7行和9行实例化的模板类都是Array,代码8行实例化的模板类是Array,代码10行实例化的模板类是Array。一共是三个实例。ﻫ答案:

A5考点:双向链表的操作ﻫ出现频率:★★★★ﻫ解析:

为了得到双向链表的长度,需要使用right指针进行遍历,直到得到NULL为止。

1

//获取链表的长度ﻫ2

int

GetLength(DbNode

*head)

//参数为链表的表头节点

3

{ﻫ4

int

count

1;

DbNode

*pnode

NULL;

6ﻫ7

if

(head

==

NULL)

//head为NULL表达链表空

{ﻫ9

return

0;ﻫ10

11

pnode

head->right;

12

while

(pnode

!=

NULL)ﻫ13

{ﻫ14

pnode

=

pnode->right;

//使用right指针遍历

15

count++;

16

}

17

18

return

count;ﻫ19

}ﻫ更多精彩内容,请到“融智技术学苑rzchina”

使用模板有什么缺陷?如何避免?ﻫ6考点:理解模板编程的缺陷ﻫ出现频率:★★★ﻫ解析:ﻫtemplates(模板)是节省时间和避免代码反复的极好方法,我们可以只输入一个类模板,就能让编译器实例化所需要的很多个特定类及函数。类模板的成员函数只有被使用时才会被实例化,所以只有在每一个函数都在实际中被使用时,我们才会得到这些函数。

的确这是一个很重要的技术,但是假如不小心,使用模板也许会导致代码膨胀。什么是代码膨胀?请看下面的例子:ﻫ1

template

2

class

3

{

4

public:ﻫ5

void

work()

6

{

7

cout

<<

"work()

<<

endl;

8

cout

<<

num

<<

endl;

9

}ﻫ10

};

11

12

int

main()

13

{

14

Av1;ﻫ15

Av2;ﻫ16

Av3;

17

Av4;

18

v1.work();ﻫ19

v2.work();

20

v3.work();ﻫ21

v4.work();

22

return

0;ﻫ23

}

类模板A取得一个类型参数T,并且它尚有一个类型为int的参数,一个非类型参数(non-type

parameter),与类型参数相比,虽然非类型参数不是很通用,但他们是完全合法的。在本例中,由于num的不同,代码14到17行的调用将会生成了三个A的实例,然后在18~21行又生成了不同的函数调用。

虽然这些函数做了相同的事情(打印一个“work()”和num),但他们却有不同的二进制代码。这就是所说的由于模板导致的代码膨胀。也就是说,虽然源代码看上去紧凑而整洁,但是目的代码却臃肿而松散,会严重影响程序的运营效率。

如何避免由于这种代码膨胀呢?有一个原则,就是把C++模板中与参数无关的代码分离出来。也就是让与参数无关的代码只有一份拷贝。对类模板A可以进行如下地修改:

1

templateﻫ2

class

Baseﻫ3

{ﻫ4

public:

5

void

work(int

num)

6

{

7

cout

<<

"work

";ﻫ8

cout

<<

num

<<

endl;ﻫ9

10

};ﻫ11ﻫ12

templateﻫ13

class

Derived

:

public

Base

14

{ﻫ15

public:

16

void

work()ﻫ17

{ﻫ18

Base::work(num);

19

}ﻫ20

};ﻫ21

22

int

main()

23

{ﻫ24

Derivedd1;ﻫ25

Derivedd2;

26

Derivedd3;

27ﻫ28

d1.work();ﻫ29

d2.work();ﻫ30

d3.work();

31

return

0;ﻫ32

}

程序中work的参数版本是在一个Base类(基类)中的。与Derived类同样,Base类也是一个类模板,但是与Derived类不同样的是,它参数化的仅仅是类型T,而没有num。因此,所有持有一个给定类型的Derived将共享一个单一的Base类。比如代码24~26行实例化的模板类都共享Base模板类,从而他们的成员函数都共享Base模板类中的work这个单一的拷贝。

答案:

模板的缺陷:不本地使用模板会导致代码膨胀,即二进制代码臃肿而松散,会严重影响程序的运营效率。ﻫ解决方法:把C++模板中与参数无关的代码分离出来。7如何建立一个双向链表?

考点:双向链表的操作

出现频率:★★★★

解析:ﻫ双向链表的定义如下:ﻫ1

typedef

struct

DbNode

2

{

3

int

data;

//节点数据ﻫ4

DbNode

*left;

//前驱节点指针ﻫ5

DbNode

*right;

//后继节点指针ﻫ6

}

DbNode;

(1)建立双向链表:为方便,这里定义了三个函数:ﻫq

CreateNode()根据数据来创建一个节点,返回新创建的节点。ﻫq

CreateList()函数根据一个节点数据创建链表的表头,返回表头节点。

q

AppendNode

()函数总在表尾插入新节点(其内部调用CreateNode()生成节点),返回表头节点。

1

//根据数据创建创建节点

2

DbNode

*CreateNode(int

data)

3

{ﻫ4

DbNode

*pnode

=

(DbNode

*)malloc(sizeof(DbNode));

pnode->data

=

data;

6

pnode->left

=

pnode->right

=

pnode;

//创建新节点时ﻫ7

//让其前驱和后继指针都指向自身ﻫ8

return

pnode;

9}

10ﻫ11

//创建链表ﻫ12

DbNode

*CreateList(int

head)

//参数给出表头节点数据ﻫ13

{

//表头节点不作为存放故意义数据的节点

14

DbNode

*pnode

(DbNode

*)malloc(sizeof(DbNode));

15

pnode->data

head;

16

pnode->left

=

pnode->right

pnode;ﻫ17

18

return

pnode;

19

}ﻫ20ﻫ21

//插入新节点,总是在表尾插入;

返回表头节点

22

DbNode

*AppendNode(DbNode

*head,

int

data)

//参数1是链表的表头节点,

23

{

//参数2是要插入的节点,其数据为data

24

DbNode

*node

=

CreateNode(data);

//创建数据为data的新节点

25

DbNode

*p

=

head,

*q;

26

27

while(p

!=

NULL)

28

{

29

q

=

p;

30

=

p->right;

31

}

32

q->right

=

node;

33

node->left

=

q;ﻫ34ﻫ35

return

head;

36

}ﻫ我们可以使用其中的CreateList()和AppendNode()来生成一个链表,下面是一个数据生成从0到9具有10个节点的循环链表。

1

DbNode

*head

CreateList(0);

//生成表头,表头数据为0ﻫ2ﻫ3

for

(int

1;

i

<

10;

i++)ﻫ4

{

5

head

AppendNode(head,

i);

//添加9个节点,数据为从1到9

6

}

8考点:函数模板与类模板的基本概念和区别

出现频率:★★★ﻫ解析:

(1)什么是函数模板和类模板。

函数模板是一种抽象函数定义,它代表一类同构函数。通过用户提供的具体参数,C++编译器在编译时刻可以将函数模板实例化,根据同一个模板创建出不同的具体函数,这些函数之间的不同之处重要在于函数内部一些数据类型的不同,而由模板创建的函数的使用方法与一般函数的使用方法相同。函数模板的定义格式如下:ﻫ1

templateFunction_Definition

其中,Function_Definition为函数定义;TYPE_LIST被称为类型参数表,是由—系列代表类型的标记符组成的,其间用逗号分隔,这些标记符的通常风格是由大写字母组成,ARG_LIST称为变量表,其中具有由逗号分隔开的多个变量说明,相称于一般函数定义中的形式参数。前面例题中的max就是函数模板的一个例子,因此这里不再此外举例。

C++提供的类模板是一种更高层次的抽象的类定义,用于使用相同代码创建不同类模板的定义与函数模板的定义类似,只是把函数摸板中的函数定义部分换作类说明,并对类的成员函数进行定义即可。在类说明中可以使用出现在TYPE_LIST中的各个类型标记以及出现在ARG_LIST中的各变量。ﻫ1

template<<棋板参数表>>ﻫ2

class<类模板名>ﻫ3

{<类模板定义体>},ﻫ例如我们需要定义一个表达平面的点(Point)类,这个类有两个成员变量分别表达横坐标和纵坐标,并且这两个坐标的类型可以是int、float、double等等类型。因此也许写出类似Point_int_int、Point_float_int、Point_float_float等这样的类。通过类模板,我们只需要写一个类。

1

#includeﻫ2

using

namespace

std;ﻫ3

templateﻫ5

class

Point_T

6

{ﻫ7

public:ﻫ8

T1

a;

//成员a为T1类型ﻫ9

T2

b;

//成员b为T2类型

10

Point_T()

:

a(0),

b(0)

{}

//默认构造函数ﻫ11

Point_T(T1

ta,

T2

tb)

:

a(ta),

b(tb)

{}

//带参数的构造函数ﻫ12

Point_T&

operator=(Point_T

&pt);

//赋值函数

13

friend

Point_T

operator

+(Point_T

&pt1,

Point_T

&pt2);

//重载+ﻫ14

};

15ﻫ16

template

17

Point_T&

Point_T::operator=(Point_T

&pt)

//赋值函数

18

{ﻫ19

this->a

=

pt.a;

20

this->b

=

pt.b;

21

return

*this;

22

}ﻫ23

24

templateﻫ25

Point_T

operator

+(Point_T

&pt1,

Point_T

&pt2)

//重载+ﻫ26

{

27

Point_T

temp;

28

temp.a

pt1.a

+

pt2.a;

//结果对象中的a和b分别为两个参数对象的各自a和b之和ﻫ29

temp.b

=

pt1.b

+

pt2.b;ﻫ30

return

temp;ﻫ31

}ﻫ32

33

templateﻫ34

ostream&

operator

<<

(ostream&

out,

Point_T&

pt)

//重载输出流操作符

35

{ﻫ36

out

<<

"("

<<

pt.a

<<

",

";

//输出(a,

b)

37

out

<<

pt.b

<<

")";ﻫ38

return

out;

39

}ﻫ40ﻫ41

int

main()

42

{ﻫ43

Point_T

intPt1(1,

2);

//T1和T2都是intﻫ44

Point_T

intPt2(3,

4);

//T1和T2都是intﻫ45

Point_T

floatPt1(1.1f,

2.2f);

//T1和T2都是float

46

Point_T

floatPt2(3.3f,

4.4f);

//T1和T2都是floatﻫ47

48

Point_T

intTotalPt;

49

Point_T

floatTotalPt;ﻫ50

51

intTotalPt

=

intPt1

+

intPt2;

//类型为Point_T的对象相加ﻫ52

floatTotalPt

=

floatPt1

+

floatPt2;

//类型为Point_T的对象相加

53

54

cout

<<

intTotalPt

<<

endl;

//输出Point_T的对象ﻫ55

cout

<<

floatTotalPt

<<

endl;

//输出Point_T的对象

56ﻫ57

return

0;ﻫ58

}

Point_T类就是一个类模板,它的成员a和b分别为T1和T2类型,这里我们还实现了它的构造函数、赋值函数、“+”运算符的重载以及输出流操作符“<<”的重载。ﻫ使用Point_T类非常方便,我们可以进行各种类型的组合。ﻫ代码43、44行,定义了两个Point_T类的对象intPt1和intPt2,表白这两个对象的成员a和b都是int类型。ﻫ代码45、46行,定义了两个Point_T类的对象floatPt1和floatPt2,表白这两个对象的成员a和b都是float类型。

代码51行,对intPt1和intPt2进行对象加法,结果保存到intTotalPt中,此过程先调用“+”函数,再调用了“=”函数。

代码52行,与51行类似,只是相加的对象和结果对象都是Point_T类的对象。

代码54、55行,输出对象intTotalPt和floatTotalPt的内容。

可以看出,通过使用类模板Point_T我们可以创建不同的类,大大提高了代码的可维护性以及可重用性。

有一些概念需要区别:函数模板与模板函数,类模板和模板类是不同的意思。ﻫ函数模板的重点是模板,它表达的是一个模板,用来生产函数。例如前面例题的max是一个函数模板。而模板函数的重点是函数,它表达的是由一个模板生成而来的函数。例如max,max等都是模板函数。ﻫ类模板和模板类的区别与上面的类似,类模板用于生产类,例如Point_T就是一个类模板。而模板类是由一个模板生成而来的类,例如Point_T和Point_T都是模板类。

(2)函数模板和类模板有什么区别。ﻫ在面试例题1的程序代码中,我们在使用函数模板max时不一定要必须指明T的类型,函数模板max的实例化是由编译程序在解决函数调用时自动完毕的,当调用max(1,

2)时自动生成实例max,而调用max(1.1f,

2.2f)时自动生成实例max。当然也可以显示指定T的类型。

对于本例题的类模板Point_T来说,其实例化必须被显示地指定,比如Point_T、Point_T。

答案:

函数模板是一种抽象函数定义,它代表一类同构函数。类模板是一种更高层次的抽象的类定义。ﻫ函数模板的实例化是由编译程序在解决函数调用时自动完毕的,而类模板的实例化必须由程序员在程序中显式地指定。9约瑟夫问题的解答ﻫ考点:循环链表的操作ﻫ出现频率:★★★★ﻫ编号为1,2,....,N的N个人按顺时针方向围坐一圈,每人持有一个密码(正整数),一开始任选一个正整数作为报数上限值M,从第一个人开始按顺时针方向自1开始顺序报数,报到M时停止报数。报M的人出列,将他的密码作为新的M值,从他在顺时针方向上的下一个人开始重新从1报数,如此下去,直至所有人所有出列为止。试设计一个程序求出出列顺序。ﻫ解析:

显然当有人退出圆圈后,报数的工作要从下一个人开始继续,而剩下的人仍然是围成一个圆圈的,因此可以使用循环单链表,由于退出圆圈的工作相应着表中结点的删除操作,对于这种删除操作频繁的情况,选用效率较高的链表结构,为了程序指针每一次都指向一个具体的代表一个人的结点而不需要判断,链表不带头结点。所以,对于所有人围成的圆圈所相应的数据结构采用一个不带头结点的循环链表来描述。设头指针为p,并根据具体情况移动。

为了记录退出的人的先后顺序,采用一个顺序表进行存储。程序结束后再输出依次退出的人的编号顺序。由于只记录各个结点的data值就可以,所以定义一个整型一维数组。如:int

quit[n];n为一个根据实际问题定义的一个足够大的整数。

程序代码如下:

1

#include

2

using

namespace

std;

3ﻫ4

/*

结构体和函数声明

*/ﻫ5

typedef

struct

nodeﻫ6

{ﻫ7

int

data;

node

*next;ﻫ9

}

node;ﻫ10ﻫ11

node

*node_create(int

n);ﻫ12

13

//构造节点数量为

n

的单向循环链表ﻫ14

node

*

node_create(int

n)ﻫ15

16

node

*pRet

=

NULL;

17ﻫ18

if

(0

!=

n)ﻫ19

{

20

int

n_idx

1;ﻫ21

node

*p_node

=

NULL;

22

23

/*

构造

node

*/ﻫ24

p_node

=

new

node[n];ﻫ25

if

(NULL

==

p_node)

//申请内存失败,返回NULL

26

27

return

NULL;ﻫ28

}

29

elseﻫ30

{

31

memset(p_node,

0,

*

sizeof(node));

//初始化内存ﻫ32

}ﻫ33

pRet

=

p_node;ﻫ34

while

(n_idx

n)

//构造循环链表

35

//初始化链表的每个节点,从1到nﻫ36

p_node->data

n_idx;

37

p_node->next

p_node

1;ﻫ38

p_node

p_node->next;

39

n_idx++;ﻫ40

41

p_node->data

=

n;ﻫ42

p_node->next

=

pRet;

43

44

45

return

pRet;

46

}ﻫ47ﻫ48

int

main()ﻫ49

{

50

node

*pList

=

NULL;ﻫ51

node

*pIter

NULL;;ﻫ52

int

n

=

20;ﻫ53

int

m

=

6;ﻫ54

55

/*

构造单向循环链表

*/ﻫ56

pList

node_create(n);ﻫ57ﻫ58

/*

Josephus

循环取数

*/ﻫ59

pIter

=

pList;ﻫ60

%=

n;

61

while

(pIter

!=

pIter->next)

62

{

63

int

=

1;

64ﻫ65

/*

取到第

m-1

个节点

*/

66

for

(;

m

-

1;

i++)ﻫ67

{ﻫ68

pIter

pIter->next;

69

}

70

71

/*

输出第

m

个节点的值

*/ﻫ72

printf("%d

",

pIter->next->data);ﻫ73ﻫ74

/*

从链表中删除第

个节点

*/

75

pIter->next

=

pIter->next->next;ﻫ76

pIter

=

pIter->next;

77

}ﻫ78

printf("%d",

pIter->data);ﻫ79

80

/*

释放申请的空间

*/ﻫ81

delete

[]pList;

82

return

0;ﻫ83

}10举例说明什么是泛型编程ﻫ考点:泛型编程的基本概念ﻫ出现频率:★★★

解析:ﻫ泛型编程指编写完全一般化并可反复使用的算法,其效率与针对某特定数据类型而设计的算法相同。所谓泛型,是指具有在多种数据类型上皆可操作的含意,在C++中事实上就是使用模板实现。ﻫ举一个简朴的例子,比如我们要比较两个数的大小,这两个数的类型也许是int,也也许是float,尚有也许是double。一般编程时我们也许这样写函数(不考虑使用宏的情况):

1

int

max(int

a,

int

b)

//参数和返回值都是int类型ﻫ2

{ﻫ3

return

a

>

b?

a:

b;ﻫ4

}

5

6

float

max(float

a,

float

b)

//参数和返回值都是float类型

7

{ﻫ8

return

a

>

b?

a:

b;ﻫ9

}ﻫ10

11

double

max(double

a,

double

b)

//参数和返回值都是double类型ﻫ12

{

13

return

a

>

b?

a:

b;ﻫ14

}ﻫ可以看到,上面写了3个重载函数,他们的区别仅仅只是类型(参数及返回值)不同,而函数体完全同样。

而假如使用模板,我们可以这样写:ﻫ1

template

//class也可用typename替换ﻫ2

T

max(T

a,

T

b)

//参数和返回值都是T类型

3

{ﻫ4

return

a

>

b?

a:

b;ﻫ5

}ﻫ这里的class不代表对象的类,而是类型(可用typename替换)。这样max函数的各个参数以及返回值类型都为T,对于任意类型的两个数,我们都可以调用max求大小,测试代码如下:ﻫ1

int

main()ﻫ2

{ﻫ3

cout

<<

max(1,

2)

<<

endl;

//隐式调用int类型的max

4

cout

<<

max(1.1f,

2.2f)

<<

endl;

//隐式调用float类型的maxﻫ5

cout

<<

max(1.11l,

2.22l)

<<

endl;

//隐式调用double类型的maxﻫ6

cout

<<

max('A',

'C')

<<

endl;

//隐式调用char类型的maxﻫ7

cout

<<

max(1,

2.0)

<<

endl;

//必须指定int类型ﻫ8ﻫ9

return

0;ﻫ10

}ﻫ程序执行结果如下:ﻫ1

2ﻫ2

2.2ﻫ3

2.22

5

2ﻫ上面的程序中对于int、float、double、以及char类型的都进行了测试。这里需要注意的是第7行的测试中显示的指定了类型为int,这是由于参数1为int类型,参数2.0为double类型,此时假如不指定是使用什么类型,会产生编译的模糊性,即编译器不知道是需要调用int版本的max还是调用double版本的max函数。

此外,T作为max函数的各参数以及返回值类型,它几乎可以是任意类型,即除了基本类型(int、float、char等),还可以是类,当然这个类需要重载“>”操作符(由于max函数体使用了这个操作符)。ﻫ显然,使用泛型编程(模板)可以极大地增长了代码的重用性。11考点:单链表的操作

出现频率:★★★★

已知两个链表head1

和head2

各自有序,请把它们合并成一个链表仍然有序。使用非递归方法以及递归方法。ﻫ解析:ﻫ一方面介绍非递归方法。由于两个链表head1

和head2都是有序的,所以我们只需要找把较短链表的各个元素有序的插入到较长的链表之中就可以了。ﻫ源代码如下:

node*

insert_node(node

*head,

node

*item)

//head

!=

NULL

2

{ﻫ3

node

*p

head;

node

*q

=

NULL;

//始终指向p之前的节点

5

6

while(p->data

item->data

&&

p

!=

NULL)ﻫ7

{ﻫ8

p;ﻫ9

p

p->next;ﻫ10

}ﻫ11

if

(p

==

head)

//插入到原头节点之前ﻫ12

{ﻫ13

item->next

p;

14

return

item;

15

}

16

//插入到q与p之间之间ﻫ17

q->next

=

item;ﻫ18

item->next

=

p;

19

return

head;

20

}ﻫ21ﻫ22

/*

两个有序链表进行合并

*/ﻫ23

node*

merge(node*

head1,

node*

head2)ﻫ24

{ﻫ25

node*

head;

//合并后的头指针

26

node

*p;ﻫ27

node

*nextP;

//指向p之后

28ﻫ29

if

head1

==

NULL

)

//有一个链表为空的情况,直接返回另一个链表ﻫ30

{

31

return

h

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论