static和const关键字的作用、指针和引用区别、哈希表处理冲突方法---面试题

一、static和const关键字的作用?
static关键字的作用:
(1)函数体内static变量的作用范围为该函数体,不同于auto变量,该变量的内存只被分配一次,因此其值在下次调用时仍维持上次的值;
(2)在模块内的static全局变量可以被模块内所用函数访问,但不能被模块外其它函数访问;
(3)在模块内的static函数只可被这一模块内的其它函数调用,这个函数的使用范围被限制在声明它的模块内;
(4)在类中的static成员变量属于整个类所拥有,对类的所有对象只有一份拷贝;
(5)在类中的static成员函数属于整个类所拥有,这个函数不接收this指针,因而只能访问类的static成员变量。
const关键字的作用:
(1)欲阻止一个变量被改变,可以使用const关键字。在定义该const变量时,通常需要对它进行初始化,因为以后就没有机会再去改变它了;
(2)对指针来说,可以指定指针本身为const,也可以指定指针所指的数据为const,或二者同时指定为const;
(3)在一个函数声明中,const可以修饰形参,表明它是一个输入参数,在函数内部不能改变其值;
(4)对于类的成员函数,若指定其为const类型,则表明其是一个常函数,不能修改类的 成员变量;
(5)对于类的成员函数,有时候必须指定其返回值为const类型,以使得其返回值不为“左值”。

二、1.指针和引用的定义和性质区别:

(1)指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元;而引用跟原来
的变量实质上是同一个东西,只不过是原变量的一个别名而已。如:

						int a=1;int *p=&a;
						int a=1;int &b=a;

上面定义了一个整形变量和一个指针变量p,该指针变量指向a的存储单元,即p的值是a存储单元的地址。
而下面2句定义了一个整形变量a和这个整形a的引用b,事实上a和b是同一个东西,在内存占有同一个存储单
元。
(2)引用不可以为空,当被创建的时候,必须初始化,而指针可以是空值,可以在任何时候被初始化。
(3)可以有const指针,但是没有const引用;
(4)指针可以有多级,但是引用只能是一级(int **p;合法 而 int &&a是不合法的)
(5)指针的值可以为空,但是引用的值不能为NULL,并且引用在定义的时候必须初始化;
(6)指针的值在初始化后可以改变,即指向其它的存储单元,而引用在进行初始化后就不会再改变了。
(7)”sizeof引用”得到的是所指向的变量(对象)的大小,而”sizeof指针”得到的是指针本身的大小;
(8)指针和引用的自增(++)运算意义不一样;
(9)如果返回动态内存分配的对象或者内存,必须使用指针,引用可能引起内存泄漏;

2.指针和引用作为函数参数进行传递时的区别。
(1)指针作为参数进行传递:

							#include<iostream>
							#include<stdlib.h>
							using namespace std;
							void swap_int(int *a,int *b)
							{
							    int *temp=a;
							    a=b;
							    b=temp;
							}
							
							void test(int *p)
							{
							    int a=1;
							    p=&a;
							    cout<<p<<" "<<*p<<endl<<endl;;
							}
							
							int main(void)
							{
							    int a=1,b=2;
							    int *p=NULL;
							    swap_int(&a,&b);
							    cout<<a<<" "<<b<<endl<<endl;
							    test(p);
							    if(p==NULL)
							    cout<<"指针p为NULL"<<endl<<endl;
							    system("pause");
							}

swap_int函数使用指针传递参数,可以实现对实参进行改变的目的,是因为传递过来的是实参的地址,因此
使用*a实际上是取存储实参的内存单元里的数据,即是对实参进行改变,因此可以达到目的。调用test函数
运行结果为:
0x6afecc 1
指针p为NULL
在main函数中声明了一个指针p,并赋值为NULL,当调用test函数时,事实上传递的也是地址,只不过传递
的是指地址。也就是说将指针作为参数进行传递时,事实上也是值传递,只不过传递的是地址。当把指针作
为参数进行传递时,也是将实参的一个拷贝传递给形参,即上面程序main函数中的p何test函数中使用的p不
是同一个变量,存储2个变量p的单元也不相同(只是2个p指向同一个存储单元),那么在test函数中对p进
行修改,并不会影响到main函数中的p的值。如果要想达到也同时修改的目的的话,就得使用引用了。

(2)将引用作为函数的参数进行传递。
在讲引用作为函数参数进行传递时,实质上传递的是实参本身,即传递进来的不是实参的一个拷贝,因此对
形参的修改其实是对实参的修改,所以在用引用进行参数传递时,不仅节约时间,而且可以节约空间。

			#include<iostream>
			#include<stdlib.h>
			using namespace std;
			
			void test(int &a)
			{
			    cout<<&a<<" "<<a<<endl<<endl;
			}
			
			int main(void)
			{
			    int a=1;
			    cout<<&a<<" "<<a<<endl<<endl;
			    test(a);
			    system("pause");
			}

所以在引用进行参数传递时,事实上传递的是实参本身而不是拷贝副本。所以在上述要达到同时修改指针的
目的的话,就得使用引用了。

							#include<iostream>
							#include<stdlib.h>
							using namespace std;
							
							void test(int *&p)
							{
							    int a=1;
							    p=&a;
							    cout<<p<<" "<<*p<<endl<<endl;
							}
							
							int main(void)
							{
							    int *p=NULL;
							    test(p);
							    if(p!=NULL)
							    cout<<"指针p不为NULL"<<endl<<endl;
							    cout<<p<<" "<<*p<<endl<<endl;
							    system("pause");
							}

三、哈希表处理冲突的方法
1、基本概念
哈希表,也叫散列表,是根据关键字而直接进行访问的数据结构。也就是说,它将关键字通过某种规则映射到数组中某个位置,以加快查找的速度。这个映射规则称为哈希函数(散列函数),存放记录的数组称为哈希表。哈希表建立了关键字和存储地址之间的一种直接映射关系。
2、处理冲突的方法
(1) 链地址法
链地址法是指把所有的冲突关键字存储在一个线性链表中,这个链表由其散列地址唯一标识。
(2) 开放定址法
开放定址法是指可存放新表项的空闲地址,既向它的同义词表项开放,又向它的非同义词表项开放。其数学递推公式为(Hi表示冲突发生后第i次探测的散列地址)
Hi = (H(key) + di) % m
式中,i = 1,2,…,k,m为散列表表长,di为增量序列。di通常有以下几种取法:
当di = 1,2,…,m - 1时,称为线性探测法。其特点是,冲突发生时顺序查看表中下一个单元,直到找出一个空单元或查遍全表。
当di = 12,-12,22,-22,…,k2,-k2时,又称为二次探测法。
当di = 伪随机数序列时,称为伪随机探测法。
(3) 再散列法
当发生冲突时,利用另一个哈希函数再次计算一个地址。直到冲突不再发生。
(4) 建立一个公共溢出区
一旦由哈希函数得到的地址冲突,就都填入溢出表。

猜你喜欢

转载自blog.csdn.net/N1314N/article/details/89412598