C++常见问题

1.反转链表

http://c.biancheng.net/view/8105.html

// 非递归
LinkNode* ReserveLinkNode(LinkNode* head){
  if(NULL == head || NULL == head->next)
    return head;
  LinkNode* pre = NULL;
  LinkNode* cur = head;
  LinkNode* next = NULL;
  while(cur){
    next = cur->next;
    cur->next = pre;
    pre = cur;
    cur = next;
  }
}
// 递归
LinkNode* ReserveLinkNode(LinkNode* head){
  if(head == NULL && head->next == NULL)
    return head;
  LinkNode* newNode = ReserveLinkNode(head->next);
  head->next->next = head;
  head->next = NULL;
  return newNode;
}

2.删除任意链表节点

pNode->next = pNode->next->next;

3.多态

多态的条件:

  1. 父类有虚函数;
  2. 子类改写了虚函数;
  3. 通过父类的指针或引用来调用虚函数, 在运行时,绑定到不同的子类中,产生不同的行为

重载:

同名不同参数(在同一个类中实现的),重载根据参数列表实现的,返回值类型可以不同

重写:

同名同参同返回值,执行过程中决定的,在父子类中实现

隐藏:

子类中重定义父类中同名函数,在父子类中实现,参数列表可以不同,返回值也可以不同

4.双向链表插入和删除

1.s->prior = p;//将p(指向结点的指针)赋值给s的前驱
2.s->next = p->next;	//将p->next所指的结点,用s->next代替它指向这个结点
3.p->next->prior = s;	//将指向数据元素为e的结点的指针s,现在用p->next->prior代替s指向此结点
4.p->next = s;	//用p->next代替s指向数据元素为e的结点

1.p->prior->next = p->next;	//将 p->next 指向的结点,现在用 p->prior->next 指向此结点
2.p->next->prior = p->prior;	//将 p->prior 所指的结点,现用 p->next->prior代替其指向该结点
3.free(p);	//释放指针p(相当于释放p所指向的结点)

5.快排

// ==========递归================
void QuickSort(std::vector<int>& arr,int left,int right){
  if(left > right)
    return;
  int i = left;
  int j = right;
  int key = arr[left];
  
  while(i<j){
    while(arr[j] <= key && i<j){
      j--;
    }
    arr[i] = arr[j];
    while(arr[i] > = key && i<j){
      i++;
    }
    arr[j] = arr[i];
  }
  arr[i] = key;
  QuickSort(arr,0,i-1);
  QuickSort(arr,i+1,right);
}

// ============非递归=================
// 划分算法
int Partition(std::vector<int>& arr,int low,int high){
  int i = low;
  int j = high;
  int key = arr[low];
    while(i<j){
    while(arr[j] <= key && i<j){
      j--;
    }
    arr[i] = arr[j];
    while(arr[i] >= key && i<j){
      i++;
    }
    arr[j] = arr[i];
  }
  arr[i] = key;
  return i;
}

// 非递归
void QuickSot_non_recursive(std::vector<int>& arr,int left,int right){
  if(left > right)
    return;
    
  std::statck<int> s;
  int index = Partition(arr,left,right);
  if(index -1 > left){
    s.push(left);
    s.push(index-1);
  }
  if(index +1<right){
    s.push(index+1);
    s.push(right);
  }
  
  while(!s.empty()){
    int r = s.top();
    s.pop();
    int l = s.top();
    s.pop();
    index = Partition(arr,l,r);
    if(index -1 > l){
      s.push(l);
      s.push(index-1);
    }
    if(index+1<r){
      s.push(index+1);
      s.push(r);
    }
  }
}

6.冒泡改进

void BubbleSort(std::vector<int>& arr){
  for(int i=0;i<arr.size();i++){
    int n = 0;
    for(int j = i+1;j<arr.size();j++){
      if(arr[i]>arr[j]){
        n++;
        int tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
      }
    }
    if(n == 0){
      printf("第%d次,排序了%d次,完成排序\n",i-1,n);
      break;
    }else{
      printf("第%d次,排序了%d次\n",i,n);
    }
  }
}

7.二叉树遍历

前序:根->左->右

中序:左->根->右

后序:左->右->根

struct BinaryNode{
  char ch;
  BinaryNode* lChild;
  BinaryNode* rChild;
}

void Per_Recursion(BinaryNode* root){
  if(NULL != Rroot)
    return;
  
  printf("%s\n",root->ch);
  Per_Recursion(root->left);
  Per_Recursion(root->right);
}

void Mid_Recursion(BinaryNode* root){
  if(NULL != Rroot)
    return;
  
  Per_Recursion(root->left);
  printf("%s\n",root->ch);
  Per_Recursion(root->right);
}

void Lat_Recursion(BinaryNode* root){
  if(NULL != Rroot)
    return;
  
  Per_Recursion(root->left);
  Per_Recursion(root->right);
  printf("%s\n",root->ch);
}

8.哈希结构

通过哈希函数(hashFunc) 使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快找到该元素。

1.直接定址法

  • 取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B ;
    优点:简单、高效 ;
    缺点:需要事先知道关键字的分布情况

2.除留余数法(常用)

  • 设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数i作为除数,按照哈希函数:Hash(key) = key% i(p<=m), 将关键码转换成哈希地址;

3.哈希冲突

  • 不同关键字通过相同哈希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。

解决哈希冲突两种常见的方法是:闭散列和开散列;

9.关联式容器和序列式容器

关联式容器:关联式容器,每笔数据(每个数据)都有一个键值(key)和一个实值(value);

序列式容器:所谓序列式容器,其中的元素都是可序的,但是未必都是有序的;

10.get post区别

1.功能不同

get:从服务端获取数据

post:从服务器传送数据

2.过程可见性

get直接将请求参数放在url中,可见

post通过请求体发送给服务器,不可见

3.获取值不同

get是从Request.QueryString获取值

post是从Request.Form获取值

4.传送数据量不同

get传送的数据量较小

post传送的数据量较大,理论上没有大小限制

5.安全性不同

post比get安全

11.结构体成员内存对齐规则

原则1:结构体中元素是按照定义顺序一个一个放到内存中去的,但并不是
紧密排列的。从结构体存储的首地址开始,每一个元素放置到内存中时,它都
会认为内存是以它自己的大小来划分的,因此元素放置的位置一定会在自己宽度的整数倍上开始(以结构体变量首地址为0计算)。

原则2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储。(struct a里存有struct b,b里有char,int,double等元素,那b应该从8的整数倍开始存储。)

原则3:结构体的总大小,也就是sizeof的结果,必须是其内部最大成员的整数倍,不足的要补齐。

在设计结构体的时候,一般会尊照一个习惯,就是把占用空间小的类型排在前面,占用空间大的类型排在后面,这样可以相对节约一些对齐空间。

12.常见问题

  • 构造函数不能是虚函数或者const函数

虚函数是存在于内存空间的,构造函数调用虚函数指针时,本身还没有被实例化,不存在为虚函数指针开辟的内存空间,所以本身就是矛盾的,构造函数不能是虚函数。

虚函数本身是父类函数在动态绑定时根据动态类型来调用对应的子类函数,而构造函数是在

初始化造值,const不能赋值

  • 虚函数不能是静态函数

虚函数在调用vptr指针时,需要调用this指针去找对应的vptr指针,vptr指针找到对应的虚函数表,static本身不属于任何一个类中任何一个对象和实例,没有this指针,所以虚函数不能是静态函数。
13.递归优缺点
1.代码更简洁清晰,可读性更好;
2.消耗性能
3.遍历次数过多可能会使栈溢出,造成程序崩溃
4.很多计算重复

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值