几个小问题的整理

1char *GetMemory()

{

       char p[]="hello world";

       return p;

}

 

void main()

{

       char *p = GetMemory();

       printf(p);

}

 

出自林锐的面试题。问题出在GetMemory返回了指向局部对象(堆栈)的指针, 调用printf时会破坏掉p指向的内容,从而导致输出的不确定性。

如果改成:

char *GetMemory()

{

       char *p="hello world";

       return p;

}

就能正常输出“hello world”, 它们之间的区别在哪呢?

p[]是在堆栈上分配了的数组, 并被初始化为“hello world”p是数组首地址。

p是定义的一个指针变量,并指向了“hello world”, “hello world”是在编译阶段分配的空间,存在静态存储区。不能对“hello world”的值进行更改,因为它是个常量。

 

2

void Test(void)

{

  char *str = (char *) malloc(100);

  strcpy(str, “hello”);

  free(str); //str的值没变,但指向的内容变了。

  if(str !=  NULL)

       {

               strcpy(str, “world”);

       printf(str);

}

char *str1 = (char *) malloc(10);//提示对话框

}

执行上述代码可以输出“world”, 但是存在隐患。

因为在free(str)后,str成为了野指针,对那片内存区域更改内容后,如果继续分配内存,虽然执行时没有问题,但是在调试时vc在分配内存空间时会检查堆内容的一致性,如果可分配堆的内容被篡改了,会弹出对话框:user breakpoint called from code at 0x7c941230.

点击确定后,执行完毕后,output窗口会提示:

HEAP[test.exe]: HEAP: Free Heap block 30fd8 modified at 31000 after it was freed

 

3写出一个比较相同类型的数据是否相等的函数。

函数模板:

template<typename T> bool compare(T a, T b)

//template<class T> bool compare(T a, T b)

{

       return a == b;

}

 

void main()

{

       string a = "ni";

       string b = "ni";

       bool c = compare(a, b);

       c=compare(“ni”, “hao”);//在静态区存了“ni”, “hao”,是常量,见问题1

       c = compare(1.0,2.0);

 c = compare<int>(1,3);

}

 

4strcpy覆盖问题:(可以)

比如:char p[]=”hello world”;

          strcpy(p, p+2);

此函数与memcpy, memmove的区别,见“我眼中的数据对齐”。

 

5、在使用STL容器时,要先使用Using namespace std,指定名字空间;或者使用std::。因为这些容器都定义在std名字空间内(_STD_BEGIN)。

vector是序列式的,相当于数组,可以随机访问。

set, multiset, map, multimap是关联式式的,都是基于红黑树的结构。

容器都可以使用Iterator来进行遍历,定义iterator时要指定名字域,比如map<string,int>::iterator。

set,  multiset:是只有keyset不允许重复,multiset可以重复。那multiset有什么意义呢?

Map, multimap:是<key, value>的形式。Mapkey唯一;multimap不唯一,比如一个人有好几个电话号码。

 

6hash_mapmap的区别在哪里? 查《程序设计实践》

hash_map需要hash函数,等于函数;map只需要比较函数(小于函数)

hash_map采用hash表存储,map一般采用红黑树(RB Tree)实现。

 

7、平衡二叉树(AVL树)是一种二叉查找树,并且或者是一棵空树,或者是具有下列性质的二叉树:它的左子树和右子树都是平衡二叉树,且左子树和右子树的高度之差之差的绝对值不超过1

红黑树是一种二叉查找树,红黑树并不是平衡二叉树,恰恰相反,红黑树放松了平衡二叉树的某些要求,由于一定限度的不平衡,红黑树的性能得到了提升。查老严的《数据结构》。

附:二叉排序树和二分查找以及平衡二叉树的比较。

 

8、去除字符串前后的空格。

1)使用正则表达式

2

char * trim(char * src)

{

       for(int i = 0; *(src+i) ==' '; i++)

              ;

       //src=src+i;

       strcpy(src,src+i);

 

       for(i = strlen(src)-1; i>=0; i--)

              if(*(src+i) != ' ')//可以使用s[i], 查看K&RThe c programming language

                     break;

       *(src+i+1) = '/0';

      

       return src;

}

 

9、统计文本文件的行数。

unsigned short count_lines(FILE* fp)

{

       int c, nl;

 

       if(fp==NULL)

              return 0;

 

       nl = 0;

       while ((c = fgetc(fp)) != EOF) //用fgets,fread一次读一行话,要确保数组足够大。

              if (c == '/n')

                     ++nl;

       return nl+1;

}  

 

 

附:

二叉排序树和二分查找以及平衡二叉树的比较

(1)在二叉排序树上进行查找时的平均查找长度和二叉树的形态有关:
  ①在最坏情况下,二叉排序树是通过把一个有序表的n个结点依次插入而生成的,此时所得的二叉排序树蜕化为棵深度为n的单支树,它的平均查找长度和单链表上的顺序查找相同,亦是(n+1)/2
  ②在最好情况下,二叉排序树在生成的过程中,树的形态比较匀称,最终得到的是一棵形态与二分查找的判定树相似的二叉排序树,此时它的平均查找长度大约是lgn
  ③插入、删除和查找算法的时间复杂度均为O(lgn)

(3)二叉排序树和二分查找的比较
   
就平均时间性能而言,二叉排序树上的查找和二分查找差不多。
   
就维护表的有序性而言,二叉排序树无须移动结点,只需修改指针即可完成插入和删除操作,且其平均的执行时间均为O(lgn),因此更有效。二分查找所涉及的有序表是一个向量,若有插入和删除结点的操作,则维护表的有序性所花的代价是O(n)。当有序表是静态查找表时,宜用向量作为其存储结构,而采用二分查找实现其查找操作;若有序表里动态查找表,则应选择二叉排序树作为其存储结构。

(4)平衡二叉树
   
为了保证二叉排序树的高度为lgn,从而保证然二叉排序树上实现的插入、删除和查找等基本操作的平均时间为O(lgn),在往树中插入或删除结点时,要调整树的形态来保持树的"平衡。使之既保持BST性质不变又保证树的高度在任何情况下均为O(lgn),从而确保树上的基本操作在最坏情况下的时间均为O(lgn)

注意:

     平衡二叉树(Balanced Binary Tree)是指树中任一结点的左右子树的高度大致相同。

     任一结点的左右子树的高度均相同(如满二叉树),则二叉树是完全平衡的。通常,只要二叉树的高度为O(1gn),就可看作是平衡的。

     平衡的二叉排序树指满足BST性质的平衡二叉树。

     AVL树中任一结点的左、右子树的高度之差的绝对值不超过1。在最坏情况下,n个结点的AVL树的高度约为1.44lgn。而完全平衡的二叉树度高约为lgnAVL树是接近最优的。

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值