面试题整理

1.编写实现链表排序的一种算法。说明为什么你会选择用这样的方法

//归并排序合并 ,空间复杂度O(1),时间复杂度O(nlogn)
struct ListNode
{
    int value;
    ListNode* next;
};
 
//合并
ListNode* merge(ListNode *a,ListNode *b)
{
    ListNode *result=NULL;
    if(a==NULL)
        return b;
    else if(b==NULL)
        return a;
     
    if(a->value<=b->value) 
    { 
        result=a; 
        result->next=merge(a->next,b); 
    } 
    else 
    { 
        result=b; 
        result->next=merge(a,b->next);    
    } 
    return result; 
}
 
//寻找中点
void findMid(ListNode* source, ListNode** first, ListNode** mid) 
{ 
    ListNode* fast; 
    ListNode* slow; 
   
    if(source==NULL||source->next== NULL) 
    { 
        *first=source; 
        *mid=NULL; 
    } 
    else 
    { 
        slow=source; 
        fast=source->next; 
    
        while(fast!=NULL) 
        { 
            fast=fast->next; 
            if(fast!=NULL) 
            { 
                fast=fast->next; 
                slow=slow->next; 
            } 
        } 
   
        *first=source; 
        *mid=slow->next; 
        slow->next=NULL; 
    } 
} 
 
void listMergeSort(ListNode **p)
{
    ListNode *head=*p;
    ListNode *a,*b;
     
    if(head==NULL||head->next==NULL)
        return ;
     
    findMid(head,&a,&b);
     
    listMergeSort(&a);
    listMergeSort(&b);
     
    *p=merge(a,b);
}

2.请编写能直接实现strstr()函数功能的代码

char *strstr(const char*s1,const char*s2)

{

    const char*p=s1;

    const size_tlen=strlen(s2);

    for(;(p=strchr(p,*s2))!=0;p++)

    {

        if(strncmp(p,s2,len)==0)

            return (char*)p;

    }

    return(0);

}

3.编写反转字符串的程序,要求优化速度、优化空间。

#include <stdio.h>  
void reverse(char *_str,int _l) //反转函数,_l指要反转字串的长度  
{  
  char*p=_str,*q=_str+_l-1;  
  _l/=2;  
 while(_l>0)  
    {  
      //为了使代码得到优化 采用异或操作符进行交换  
      *p=*p^*q;  
      *q=*p^*q;  
      *p=*p^*q;  
   
      p++;  
      q--;  
      _l--;  
    }  
}  

4.在链表里如何发现循环链接?

 struct LinkNode
{
    int data;
    LinkNode *next;
};

void findx(node *head)
{
  LinkNode *s0,*s1;
  s0 = head;
  s1 = head;
  while((s0 != NULL) &&(s1 != NULL))
   { 
       s0 = s0->next;
       s1 = s1->next->next;
       if(s0 == s1)
        {
             printf("有循环链接");
        }
   }
   if((s1 == NULL) || (s0 == NULL))
     {
         printf("没有循环链接");
     }
}

5.给出洗牌的一个算法

void shuffle(int boke[])  //洗牌
{
  int i,r,t;
  for(i=0; i<54; i++)
    {
      r=(rand()%107)/2;//rand()不需要参数,它会返回一个从0到最大随机数的任意整数
      //交换
      t=boke[i];
      boke[i]=boke[r];
      boke[r]=t;
    }
}

 

6.写一个函数,检查字符是否是整数,如果是,返回其整数值

long str2Long(string str)
{
long temp=0;
for(int i=0;i<str.length();i++)
{
if(str[i]<'0'||str[i]>'9')
return 0;
else temp=temp*10+str[i]-'0';
}

return temp;
} 

7.给出一个函数来输出一个字符串的所有排列

 

8.数据库脏数据

数据库中常见的并发操作所带来了一致性问题包括:丢失的修改,不可重复读,读“脏”数据,幻读。

1.丢失的修改:一个事物的更新覆盖了另一个事物的更新。例如:事物A和B读入同一数据并修改,B提交的结果破坏了A提交的结果,导致A的修改被丢失。

2.不可重复读:一个事物两次读取同一个数据,两次读取的数据不一致。不可重复读是指事物A读取数据后,事物B执行更新操作,事务A 无法再现前一次读取结果。

a.事物A读取某一数据后,事物B对其作了修改,当事物A再次读取数据时,得到与前一次不同的值。

b.事物A按一定的条件从数据库中读取了某些数据后,事物B删除了其中部分记录,当A再次以相同条件读取时,发现某些记录消失了。

3.脏读:一个事物读取了另一个事物未提交的数据。读“脏”数据是指事物A修改某一数据,并将其写回磁盘,事物B读取同一数据后,A由于某种原因被撤销,这时A已修改过的数据恢复原值,B读到的数据就与数据库中的数据不一致,则B读到的数据为“脏”数据,即不正确的数据。

4.幻读:一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。

a.事物A按一定的条件从数据库中读取某些数据记录后,事物B插入了一些记录,当A再次按照相同条件读取数据时,发现多了一些记录。(也叫做幻影读)。

产生上述三类数据不一致性的主要原因是并发操作破坏了事物的隔离性,并发控制就是要用正确的方式调度并发操作,使一个事物的执行不受其他事物的干扰,从而避免造成数据的不一致性。

9.数据库索引:

在数据库表中,对字段建立索引可以大大提高查询速度。MySQL索引类型包括:

普通索引:

创建表:

CREATE TABLE mytable(  
ID INT NOT NULL,   
username VARCHAR(16) NOT NULL 
);  
 

创建索引:

CREATE INDEX indexName ON mytable(username(length)); 

添加索引:

ALTER mytable ADD INDEX [indexName] ON (username(length)) 

或者创建表时添加索引:

CREATE TABLE mytable(  
ID INT NOT NULL,   
username VARCHAR(16) NOT NULL,  
INDEX [indexName] (username(length))  
);  

删除索引:

DROP INDEX [indexName] ON mytable; 

唯一索引:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值的组合必须唯一

CREATE TABLE mytable(  
ID INT NOT NULL,   
username VARCHAR(16) NOT NULL,  
UNIQUE [indexName] (username(length))  
);  

主键索引:它是一种特殊的唯一索引,不允许有空值。一般是在建表的时候同时创建主键索引

CREATE TABLE mytable(  
ID INT NOT NULL,   
username VARCHAR(16) NOT NULL,  
PRIMARY KEY(ID)  
);  

组合索引:将多个字段组合到一个索引里面

创建表:

CREATE TABLE mytable(  
ID INT NOT NULL,   
username VARCHAR(16) NOT NULL,  
city VARCHAR(50) NOT NULL, 
age INT NOT NULL 
);  

添加索引:

    ALTER TABLE mytable ADD INDEX name_city_age (name(10),city,age); 

相当于创建了下面三个组合的索引:

    usernname,city,age  
    usernname,city  
    usernname  

MySQL组合索引“最左前缀”的结果。简单的理解就是只从最左面的开始组合。并不是只要包含这三列的查询都会用到该组合索引,下面的几个SQL就会用到这个组合

    SELECT * FROM mytable WHREE username="admin" AND city="郑州" 
    SELECT * FROM mytable WHREE username="admin" 
而下面几个则不会用到
    SELECT * FROM mytable WHREE age=20 AND city="郑州" 
    SELECT * FROM mytable WHREE city="郑州" 

面试题: MySQL仅能对索引最左边的前缀进行有效的查找
例如:索引(a,b),select * from table where a = a1 and b = b1和select * from table where a = a1可以走索引,但是select * from table where b = b1不走索引, 因为没有组合索引的引导列

虽然索引大大提高了查询速度,同时却会降低更新表的速度,如对表进行INSERT、UPDATE和DELETE。因为更新表时,MySQL不仅要保存数据,还要保存一下索引文件。

索引使用注意事项:

索引不会包含有NULL值的列

只要列中包含有NULL值都将不会被包含在索引中,复合索引中只要有一列含有NULL值,那么这一列对于此复合索引就是无效的。所以我们在数据库设计时不要让字段的默认值为NULL。

使用短索引

对串列进行索引,如果可能应该指定一个前缀长度。例如,如果有一个CHAR(255)的列,如果在前10个或20个字符内,多数值是惟一的,那么就不要对整个列进行索引。短索引不仅可以提高查询速度而且可以节省磁盘空间和I/O操作。

◆不要在列上进行运算

    select * from users where YEAR(adddate)<2007;

将在每个行上进行运算,这将导致索引失效而进行全表扫描,因此我们可以改成

    select * from users where adddate<‘2007-01-01’;   

解索引原理是使用一种数据结构「平衡树」(非二叉),也就是b tree,没加主键的表,它的数据无序的放置在磁盘存储器上,如果给表上了主键,那么表在磁盘上的存储结构就由整齐排列的结构转变成了树状结构,也就是上面说的「平衡树」结构,换句话说,就是整个表就变成了一个索引,主键的作用就是把「表」的数据格式转换成「索引(平衡树)」的格式放置。

10. 数据库的设计范式有三个:第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式;第二范式在第一范式的基础之上更进一层。第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中;第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。总结一下,就是:第一范式(确保每列保持原子性);第二范式(确保表中的每列都和主键相关);第三范式(确保每列都和主键列直接相关,而不是间接相关)。

11.mysql锁:排他锁 共享锁  表锁  行锁   意向锁  自增锁

12.redis和memcached区别
1)redis支持丰富的数据类型,memcached仅支持单一的k-v数据类型
2)redis支持数据持久化,如AOF和RBD,memcached不支持,重启后数据就全部丢失
3)memcached支持CAS,redis只能通过将多个操作组合到一起顺序执行的方式实现很简单的事务机制

RDB持久化方式能够在指定的时间间隔能对你的数据进行快照存储。AOF持久化方式记录每次对服务器写的操作,当服务器重启的时候会重新执行这些命令来恢复原始的数据。可以同时开启两种持久化方式, 当redis重启的时候会优先载入AOF文件来恢复原始的数据,因为在通常情况下AOF文件保存的数据集要比RDB文件保存的数据集要完整。

13.HashMap & Hashtable 的区别

它们用法几乎一模一样

1.同步特性不同

HashMap 同一时间允许多个线程同时进行操作

效率较高 但是可能出现并发错误

Hashtable 同一时间只允许一个线程进行操作

效率较低 但是不会出现并发错误

2。对于null的处理不同

HashMap 无论主键还是值都可以存放null

只不过主键要求唯一 所以只能有一个null

Hashtable 对null"零容忍"

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值