C语言学习_面试加排序算法汇总

来源:互联网 发布:七日杀低配优化补丁 编辑:程序博客网 时间:2024/05/24 05:04

1.如果函数需要传入一个指针,面试官可能会问是否需要为该指针加上const,把const加在指针不同的位置有什么区别?

指针做参数时,既可以是输入参数,也可以是输出参数。输出参数可能会改变该指针指向的地址的内容。指针作为输入参数,加上const关键字做个限定,防止修改函数外部数据,即用来防止该指针在函数体内被意外修改,能提高程序的健壮性

如果const位于星号的左侧,则const就是用来修饰指针所指向的变量,即指针指向的对象为常量;如果const位于星号的右侧,const就是修饰指针本身,即指针本身是常量。因此,[1]和[2]的情况相同,都是指针所指向的内容为常量,这种情况下不允许对内容进行更改操作,如不能*a = 3 ;[3]为指针本身是常量,而指针所指向的内容不是常量,这种情况下不能对指针本身进行更改操作,如a++是错误的;[4]为指针本身和指向的内容均为常量。

 

2.如果写的函数需要传入的参数是一个复杂类型的实例,面试官可能会问传入值参数或者引用参数有什么区别,什么时候需要为传入的引用参数加上const?

值传递:形参是实参的拷贝,改变函数形参的值并不会影响外部实参的值,这是最常用的一种传参方法,也是最简单的一种传参方法,只需要传递参数,返回值那是return考虑的;由于函数将自动产生临时变量用于复制该参数,该输入参数本来就无需保护,所以不要加const修饰

指针传递:指针传递参数从本质上来说也是值传递,它传递的是一个地址。【值传递过程中,被调函数的形参作为被调函数的局部变量来处理,即在函数内的栈中开辟内存空间以存放由主调函数放进来的实参的值,从而成了实参的一个副本。由于指针传递的是外部实参的地址,当被调函数的形参值发生改变时,自然外部实参值也发生改变。

引用传递:被调函数的形参虽然也作为局部变量在栈中开辟了内存空间,但是栈中存放的是由主调函数放进的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中实参变量(实参和形参通过引用,合二为一,说白点就是:一个人,有两个名字那种;后面想会详细说)。因此,形参的任何改动都会直接影响到实参。当不希望引用传递改变参数,加const修饰。

3.数据结构:链表、树、栈、队列以及哈希表

二叉排序树是一种比较有用的折衷方案。  数组的搜索比较方便,可以直接用下标,但删除或者插入某些元素就比较麻烦。链表与之相反,删除和插入元素很快,但查找很慢。  二叉排序树就既有链表的好处,也有数组的好处。在处理大批量的动态的数据是比较有用。

4.排序

(1)冒泡排序1:(沉底法)冒泡排序(BubbleSort)的基本概念是:依次比较相邻的两个数,将小数放在前面,大数放在后面。即在第一趟:首先比较第1个和第2个数,将小数放前,大数放后。然后比较第2个数和第3个数,将小数放前,大数放后,如此继续,直至比较最后两个数,将小数放前,大数放后。至此第一趟结束,将最大的数放到了最后。在第二趟:仍从第一对数开始比较(因为可能由于第2个数和第3个数的交换,使得第1个数不再小于第2个数),将小数放前,大数放后,一直比较到倒数第二个数(倒数第一的位置上已经是最大的),第二趟结束,在倒数第二的位置上得到一个新的最大数(其实在整个数列中是第二大的数)。如此下去,重复以上过程,直至最终完成排序。

void BubbleSortArray(int *a,int n) {       for(int i=1;i<n;i++)       {         for(int j=0;j<n-i;j++)          {               if(a[j]>a[j+1])//比较交换相邻元素                {                    int temp;                    temp=a[j]; a[j]=a[j+1]; a[j+1]=temp;                }          }       } }

冒泡排序2:其原理为从a[0]开始,依次将其和后面的元素比较,若a[0]>a[i],则交换它们,一直比较到a[n]。同理对a[1],a[2],...a[n-1]处理,即完成排序。 

void bubble(int *a,int n)     {       int i,j,temp;       for(i=0;i<n-1;i++)       {             for(j=i+1;j<n;j++) /*注意循环的上下限*/           {                 if(a[i]>a[j])               {                   temp=a[i];                   a[i]=a[j];                   a[j]=temp;               }          }      }  } 

(2)选择排序

选择法循环过程与冒泡法1一致,它还定义了记号min=i,然后依次把a[k]同后面元素比较,若a[min]>a[j],则使min=j.最后看看min=i是否还成立,不成立则交换a[min],a[i],这样就比冒泡法省下许多无用的交换,提高了效率。

void choise(int *a,int n)   {       int i,j,min,temp;       for(i=0;i<n-1;i++)       {           min=i;              /*给记号赋值*/           for(j=i+1;j<n;j++)           {              if(a[min]>a[j])                   min=j;      /*是k总是指向最小元素*/           }          if(i!=min)          /*当k!=i是才交换,否则a[i]即为最小*/           {                                             temp=a[i];               a[i]=a[min];               a[min]=temp;           }       }   }

(4)Shell(希尔)排序

先取一个小于n的整数d1作为第一个增量,把文件的全部记录分成d1个组。所有距离为dl的倍数的记录放在同一个组中。先在各组内进行直接插入排序;然后,取第二个增量d2<d1重复上述的分组和排序,直至所取的增量dt=1(dt<dt-l<;…<d2<d1),即所有记录放在同一组中进行直接插入排序为止。该方法实质上是一种分组插入方法。

斐波那契数列

1,1,2,3,5,8,13,21......

很多人喜欢用递归公式f(n)=f(n-1)+f(n-2)求解。如果分析它的递归调用树,就会发现有大量的计算是重复的,时间效率是以n的指数增加。但如果先求f(1)、f(2),再根据f(1)和f(2)求出f(3),接下来根据f(2)、f(3)求出f(4),并以此类推用一个循环求出f(n),这种计算方法的时间效率就只有O(n),比前面递归的方法要好很多





0 0
原创粉丝点击