数组---面试知识点整理

1、一个有序数列,序列中的每一个值都能够被2或者3或者5所整除,这个序列的初始值从1开始,但是1并不在这个数列中。求第1500个值是多少?

解析:2、3、5的最小公倍数是30。[ 1, 30]内符合条件的数有22个。如果能看出[ 31, 60]内也有22个符合条件的数,那问题就容易解决了。也就是说,这些数具有周期性,且周期为30。第1500个数是:1500/22=68   1500%68=4。也就是说:第1500个数相当于经过了68个周期,然后再取下一个周期内的第4个数。一个周期内的前4个数:2,3,4,5。故,结果为68*30=2040+5=2045。

2、顺序存储结构在物理上一般是连续存储,而链式存储一般不占用连续空间,相对而言,顺序存储的存储密度就大。

3、线性表最常用得操作是存取任一指定序号的元素和在最后进行插入和删除运算;进行任意位置存取,这个最省时省力的就是数组,也就是顺序表。 而且元素是在最后的位置进行插入和删除运算,也就不涉及其他元素进行位移的额外操作,最多涉及的就是去扩展空间了

4、一个5*4的矩阵,有多少个长方形?(正方形也算是长方形)

解析:可以这样理解:五行四列的表格有6*5条边,从六条边选两条(横向),从四条边中选两条(纵向),就可以确定一个矩形。C(6,2)*C(5,2)=15*10=150

5、线性结构指的是逻辑结构,而不是物理存储结构 

常用的线性结构有:线性表,堆栈,队列,双队列,数组,串。

常见的非线性结构有:二维数组,多维数组,广义表,树(二叉树等),图。

6、设有一个n行n列的对称矩阵A,将其下三角部分按行存放在一个一维数组B中,A[0][0]存放于B[0]中,那么第i行的对角元素A[i][i]存放于B中()处?

解析:“下三角”,“A[0][0]存放B[0]”,A[i][i]是第i+1行第i+1列元素,是第1+2+...+(i+1)=[(i+1)*(i+2)/2]个元素,又因为起始坐标是0。所以存放在[(i+1)*(i+2)/2]-1=[ (i+3)*i/2 ]处。

7、设有数组A[i,j],数组的每个元素长度为3字节,i的值为1到8,j的值为1到10,数组从内存首地址BA开始顺序存放,当用以列为主存放时,元素A[5,8]的存储首地址为()。?

解析:多加注意 i,j 的起始数值是从 1 开始的

Amn, m 对应行, n 对应列

行优先: Loc(aij) = Loc(a11) +[(i-1)*n + j-1 ]*sizeof(元素)

列优先: Loc(aij) = Loc(a11) + [(j-1)*m + i-1]*sizeof(元素)

这道题 m = 8 , n = 10 ; i = 5 , j = 8

列优先

Loc(aij) = BA + [(8-1)*8 + 5-1]*3 = BA + 180

8、有一个100*90的稀疏矩阵,非0元素有10个,设每个整型数占2字节,则用三元组表示该矩阵时,所需的字节数是()

解析:每个元素要用行号,列号,元素值来表示,在用三元组表示稀疏矩阵,还要三个成员来记住,矩阵的行数列数,总的元素数,所以所需的字节数是10*(1+1+1)*2+3*2=66

9、数组静态分配内存,链表动态分配内存;

数组在内存中连续,链表不连续;

数组元素在栈区,链表元素在堆区;

数组利用下标定位,时间复杂度为O(1),链表定位元素时间复杂度O(n);

数组插入或删除元素的时间复杂度O(n),链表的时间复杂度O(1)。

10、在一个元素个数为N的数组里,找到升序排在N/5位置的元素的最优算法时间复杂度是o(n),找到一个长度为n的数组中第k大的数的最优化时间复杂度为O(n)。将长度为k的数组进行partition,要比较的次数为k。在长度为n的数组中查找第k大的数字,最坏情况下要进行n-k次partition,复杂度为n+n-1+n-2+...+n-k=kn+k(k+1)/2=O(n)。

11、有两个从小到大排好序的数组,长度分别为N和M,将这两个数组合并成一个有序数组的最小比较次数是?

解析:最小比较次数的情况时,是一个数组的最小值,大于另外一个数组的最大值时。比较的次数是M和N中的最小值

最好是min(m,n),最坏是M+N-1

12、几种常见的数据结构的操作性能对比如下图所示

                       

13、对长度为n的线性表进行顺序查找,在最坏情况下所需要的比较次数为n

14、链表和数组的区别。

解析:链表:链表是一块不连续的动态空间,长度可变;链表需要按顺序检索节点,效率低;

链表的优点是可以快速插入和删除节点,大小动态分配,长度不固定。

链表不存在越界问题。

数组:数组是一快连续的空间,声明时长度就需要固定。

数组的优点是速度快,数据操作直接使用偏移地址。

数组有越界问题。

15、数组通常具有的两种基本操作是()

解析:数组是存储于一个连续存储空间中的相同数据类型的数据元素集合,通过数组元素的下标(位置序号),就可以找到存放该数组元素的存储地址,从而可以访问该数组元素的值。它通常用于实现顺序表,通常包括查找和修改运算。不过要注意的是,顺序表是一个一维数组,而多维数组则是典型的非线性结构。

另外值得说明的是,数组的特点是:

1)数组元素的数目固定,一旦定义了数组,就不再有元素的增减变化。

2)数据元素具有相同的类型。

3)数组的下标关系具有上下界的约束且下标有序。

因此,数组一般不做插入和删除操作

16、用一维数组存储二叉树时,总是以层次遍历顺序存储结点

17、稀疏矩阵在采用压缩存储后将会失去随机存储的功能。因为在这种矩阵中,非零元素的分布是没有规律的,为了压缩存储,就将每一个非零元素的值和它所在的行、列号做为一个结点存放在一起,这样的结点组成的线性表中叫三元组表,它已不是简单的向量,所以无法用下标直接存取矩阵中的元素。

18、int (*p)[3] p的含义是什么?   一个指向元素个数为3的int数组的指针

解析:首先先看小括号(因为小括号优先级最高),(*p)说明p首先肯定是一个指针。

然后再往后看[3],说应这个指针指向了一个数组,这个数组有三个元素。

再看最前面int,说明这个数组是整型的。

综合起来,是一个指向元素个数为3的整型数组的指针。

19、在一个长度为n的顺序表中删除第i个元素,要移动n-i个元素。如果要在第i个元素前插入一个元素,要后移n-i+1个元素。

20、静态链表是用数组存储节点数据,模拟链表的实现,但是没有用到指针。每个数组节点包括两部分:data域和cursor(游标)域。data存储数据,cursor指明下个元素在数组中的下标。

(1)存取第i个元素时,需要从头遍历到i-1和元素,由第i-1个节点的cursor,才能知道第i个元素存储的位置,因此和i是相关的。

(2)使用数组对元素进行存储,在定义时大小已经确定。

(3)插入和删除操作无需移动元素,只需要修改cursor游标的值即可,就像修改动态链表中的指针一样。

21、关于 int a[10]; 问下面哪些不可以表示 a[1] 的地址?

解析:A. a+sizeof(int)

 // 不正确, 在32位机器上相当于指针运算 a + 4

 B. &a[0]+1

 // 正确,数组首元素地址加1,根据指针运算就是a[1]的地址

C. (int*)&a+1

 // 正确,数组地址被强制类型转换为int*,然后加1,这样和B表示的一个意思

D. (int*)((char*)&a+sizeof(int))

 // 正确,数据地址先被转换为char*,然后加4,根据指针运算公式,向前移动4 * sizeof(char),之后被转换为int*,显然是a[1]的地址

22、设有字母序列{Q,D,F,X,A,P,N,B,Y,M,C,W},请写出按二路归并方法对该序列进行一趟扫描后的结果为:DQFXAPBNMYCW

解析:顺序如下

{Q,D,F,X,A,P,N,B,Y,M,C,W}

二路归并 第一次合并

{D ,Q} {F,X}  {A,P}  {B,N}  {M,Y}  {C,W}

二路归并 第二次合并

{D,F,Q,X} {A,B,N,P} {C,M,W,Y}

二路归并 第三次合并

{A,B,D,F,N,P,Q,X}  {C,M,W,Y}

二路归并 第四次合并

{A,B,C,D,F,M,N,P,Q,W,X,Y}

所以答案为

DQFXAPBNMYCW

23、广义表(((a,b,c),d,e,f))的长度是(1),深度是(3)

解析:广义表即我们通常所说的列表(lists)。它放松了对表元素的原子性限制,允许他们有自身结构。

广义表的长度:最大括号中的 逗号数+1 ;长度:去掉一层括号剩下的是几部分。

广义表的深度:展开后含括号的层数。深度:去掉几层括号可以到最后一部分。

24、下面哪几个语句正确的声明一个整型的二维数组()

解析:二维数组的定义方式: 

             1.    int [][] array = new int[n][m]; 

             2.    int [][] array={{1,2,3,4},{1,2,3,4},{1,2,3,4}};

方式一: 定义二维数组可以指定不定义m,但是必须定义n. 

25、数组指针和指针数组有什么区别 ?

解析:数组指针(也称行指针)定义 int (*p)[n];()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。如要将二维数组赋给一指针,应这样赋值:

              int a[3][4];

              int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。

             p=a;        //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0]

             p++;       //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][]

       所以数组指针也称指向一维数组的指针,亦称行指针。

指针数组 定义 int *p[n];[]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1是错误的,这样赋值也是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。如要将二维数组赋给一指针数组:

       int *p[3];

       int a[3][4];

       for(i=0;i<3;i++)

              p[i]=a[i];

       这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2]

所以要分别赋值。

这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。

26、若有18个元素的有序表存放在一维数组A[19]中,第一个元素放A[1]中,现进行二分查找,则查找A[3]的比较序列的下标依次为()

解析:注意第一个元素是放在A[1],一共18个元素,也就是A[1]~A[18]。

第一次: low=1,high=18 ,mid=9(9.5向下取整)。A[3]和A[9]比较。然后把A[9]右面的包括A[9]全部抛弃掉。

第二次:A[1]~A [8]. mid=4(向下取整)。然后把A[4]右面的包括A[4]全部抛弃掉

第三次:A[1]~A[3]。mid=2。然后把A[2]左面的包括A[2]全部抛弃掉。

第四次;A[3]和A[3]比较。终于找到你,还好我没放弃。

27、假设以行优先顺序存储三维数组A[5][6][7],其中元素A[0][0][0]的地址为1100,且每个元素占2个存储单元,则A[4][3][2]的地址是(1482)

解析:三维数组a[m1][m2][m3]中若按行优先存储,设a[0][0][0]的起始地址为p,每个元素占n个单元,则a[i][j][k]的起始地址为:

loc(i,j,k)=loc(i,0,0)+(j*m3+k)*n=loc(i-1,0,0)+(m2*m3+j*m3+k)*n=loc(i-2,0,0)+(2*m2*m3+j*m3+k)*n=…=p+(i*m2*m3+j*m3+k)*n

则loc(4,3,2)=1100+(4*6*7+3*7+2)*2=1482

28、1)《数据结构》对广义表的表头和表尾是这样定义的:如果广义表LS=(a1,a2...an)非空,则 a1是LS的表头,其余元素组成的表(a2,a3,..an)是称为LS的表尾。 

根据定义,非空广义表的 表头是一个元素,它 可以是原子也可以是一个子表, 而表尾则必定是子表。例如:LS=(a,b),表头为a,表尾是(b)而不是b.另外:LS=(a)的表头为a,表尾为空表(). (2)非空广义表,除表头外,其余元素构成的表称为表尾,所以非空广义表尾一定是个表。非空广义表的 表头是一个元素,它 可以是原子也可以是一个子表, 而表尾则必定是子表。

29、线性表有两种存储结构:

       1.顺序存储结构---顺序表。顺序表以数组形式出现,可以取任意下标访问,所以是一种随机存取的存储结构。

       2.链式存储结构---链表。链表以链表的形式出现,必须从头开始访问,所以是一种顺序存取的存储结构。

30、int *s[8]; //定义一个指针数组,该数组中每个元素是一个指针,每个指针指向哪里就需要程序中后续再定义了。

int (*s)[8]; //定义一个数组指针,该指针指向含8个元素的一维数组(数组中每个元素是int型)。

区分int *p[n]; 和int (*p)[n]; 就要看运算符的优先级了。

int *p[n]; 中,运算符[ ]优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组。

int (*p)[n]; 中( )优先级高,首先说明p是一个指针,指向一个整型的一维数组。

31、索引查找是在索引表和主表(即线性表的索引存储结构)上进行的查找。索引查找的过程是:首先根据给定的索引值K1,在索引表上查找出索引值等于K1的索引项,以确定K1对应的子表在主表中的开始位置和长度,然后再根据给定的关键字K2,在对应的子表中查找出关键字等于K2的元素(结点)。

对索引表或子表进行查找时,若表是顺序存储的有序表,则既可进行顺序查找,也可进行二分查找。否则只能进行顺序查找。

 

posted @ 2017-04-07 17:19  walanwalan  阅读(1771)  评论(0编辑  收藏  举报