408代码题暴力破解——混分归纳总结

408代码题一般2-3小问,(1)算法设计思想 (2)代码实现 (3)时间空间复杂度

一般408考虑到得分的正态分布,这一题一般会有最优解、次优解、以及勉强算你写的代码能实现功能。设计思想和复杂度计算和你的代码实现一致,15分的题这几种解法一般分别会有最高15、11、9分左右。

一般次优解都是数据结构的基础知识,加上题目要求实现的功能。主要和排序、树的遍历、链表的应用之一相关。排序的概率最大。

结构体定义

有可能有小问会要求定义一下用到的结构体。

二叉树定义

typedef struct BiTNode{
  int data;
  struct BiTNode *lchild,*rchild;
}BiTNode,*BiTree;

单链表定义

typedef struct LNode{
  int data;
  struct LNode *next;
}LTNode,*LinkList;

主要是记一下结构定义的格式

快排*****

一定要记,考试的时候很有可能直接排序后,就差不多解完了,直接一把梭。

注意时间复杂度为O(nlog2n) 空间复杂度O(log2n)

log以2为底n。 空间复杂度因为会用到递归栈,记住就行了。

void QuickSort(ElemType A[],int low,int high){
  if(low<high){//递归跳出的条件
    int p=Partition(A,low,high);//划分为两个子表
    QuickSort(A,low,p-1);//依次对两个子表进行递归排序
    QuickSort(A,p+1,high);
  }
}
int Partition(ElemType A[],int low,int high){//一趟划分
  ElemType p=A[low];//将当前表中第一个元素设为枢轴,对表进行划分
  while (low<high){//循环跳出条件
    while(low<high&&A[high]>=p) --high;
    A[low]=A[high];//将比枢轴小的元素移到左端
    while(low<high&&A[low]<=p) ++low;
    A[high]=A[low];//将比枢轴大的元素移到右端
  }
  A[low]=p;//将枢轴元素存放到最终位置
  return low;//返回存放枢轴元素的最终位置
}

就当写了个sort排序的函数库,考试抄下来直接用。
理解快排原理挺好记的。

一般题目数组都是int类型的 可以直接把ElemType改成int。

树的遍历

树的前中后序遍历都差不多,记得一个差不多就全记住了。层次遍历了解就行,因为需要用层次遍历的,一般都可以用前序遍历代替。

  • 树的先序遍历
void PreOrder(BiTree T){
  if (T!=NULL){
    visit(T);//访问根结点
    PreOrder(T.lchild); //递归遍历左子树
    PreOrder(T.rchild); //递归遍历右子树
  }
}

题目中使用

int xxx=0//(如需将递归的结果累加,可以考虑定义全局变量)
void main(BiTree root){
  PreOrder(root,0);
}
void PreOrder(BiTree t,int deep){
    if(t.lchild==NULL and t.rchild==NULL){ //判断是否为叶子结点

    }
    if(t.lchild !=NULL){//若左子树不空,递归遍历左子树
      PreOrder(t.lchild,deep+1); 
    }
    if(t.rchild !=NULL){//若右子树不空,递归遍历右子树
      PreOrder(t.rchild,deep+1); 
    }
}
  • 树的中序遍历
void InOrder(BiTree T){
  if (T!=NULL){
    InOrder(T.lchild); //递归遍历左子树
    visit(T);//访问根结点
    InOrder(T.rchild); //递归遍历右子树
  }
}

题目中使用

int xxx=0//(如需将递归的结果累加,可以考虑定义全局变量)
void main(BiTree root){
  InOrder(root,0);
}
void InOrder(BiTree t,int deep){
    if(t.lchild !=NULL){//若左子树不空,递归遍历左子树
      InOrder(t.lchild,deep+1); 
    }
    if(t.lchild==NULL and t.rchild==NULL){ //判断是否为叶子结点

    }
    if(t.rchild !=NULL){//若右子树不空,递归遍历右子树
      InOrder(t.rchild,deep+1); 
    }
}
  • 树的后序遍历
void PostOrder(BiTree T){
  if (T!=NULL){
    PostOrder(T.lchild); //递归遍历左子树
    PostOrder(T.rchild); //递归遍历右子树
    visit(T);//访问根结点
  }
}

题目中使用

int xxx=0//(如需将递归的结果累加,可以考虑定义全局变量)
void main(BiTree root){
  PostOrder(root,0);
}
void PostOrder(BiTree t,int deep){
    if(t.lchild !=NULL){//若左子树不空,递归遍历左子树
      PostOrder(t.lchild,deep+1); 
    }
    if(t.rchild !=NULL){//若右子树不空,递归遍历右子树
      PostOrder(t.rchild,deep+1); 
    }
    if(t.lchild==NULL and t.rchild==NULL){ //判断是否为叶子结点

    }
}
  • 树的层次遍历(含队列的申明和使用) 不建议记,一般不用,太麻烦

可以了解下队列的使用和层次遍历代码的实现。

#define MaxSize 100 //设置队列最大容量
void fuc(BiTree root){
  BiTree q[maxsize]; //申明队列,end1为头指针,end2为尾指针
  int end1=0,end2=0;
  int deep=0; //初始化深度
  BiTree lastNode; //lastNode记录当前层最后一个结点
  BiTree newlastNode; //newlastNode记录下一层最后一个结点
  lastNode=root;//lastNode初始化为根结点
  newlastNode=NULL;//newlastNode初始化为空
  q[end2++]=root;//根结点入队
  while(end1!=end2){//层次遍历,若不为空则循环
    BiTree t=q[end1++]; //拿出队头元素
    if(t.lchild==NULL and t.rchild==NULL){ //判断是否为叶子结点

    }
    if(t.lchild !=NULL){//若左孩子存在,则将左孩子加入队列
      q[end2++]=t.lchild;
      newlastNode=t.lchild; 
    }
    if(t.rchild !=NULL){//若右孩子存在,则将右孩子加入队列
      q[end2++]=t.rchild;
      newlastNode=t.rchild;
    }
    if(t==lastNode){//若该结点为本层最后一个结点
      lastNode=newlastNode;
      deep+=1//层数加一
    }
  }
}

链表

单链表头插法逆置链表

将原链表中的头结点和第一个元素节点断开(令其指针域为空),先构成一个新的空表,然后将原链表中各结点,从第一个结点起,依次插入这个新表的头部(即令每个插入的结点成为新的第一个元素结点)

void reverList(LNode *L){
  LNode *temp=L.next;//记录除头结点外的第一个结点
  LNode *q;//用来记录后继结点
  L.next=NULL;//原头结点令其断开
  while(temp!=NULL){
    q=temp.next;//q结点记录temp的后继结点
    temp.next=L.next;//将后继结点依次插入新表头部
    L.next=temp;
    temp=q;
  }
}

并查集

以判断图是否有环为例,因为图的顶点元素是字母,所以用int数组表示并查集(字母的次序和下标本身有对应关系),否则需要根据题目定义结构体,我觉得这种题一般不会考。就当学一下并查集。

int hasCyclic(int g[5][5]){//g[5][5]为二维数组表示的邻接矩阵
  int S[5];//定义、初始化并查集
  for(int i=0;i<5;i++) s[i]=-1;
  for(int i=0;i<5;i++)
    for(int j=i+1;j<5;j++)
      if(g[i][j]>0){//结点i、j之间有边
        int iroot=Find(S,i);//通过并查集找到i所属集合
        int jroot=Find(S,j);//通过并查集找到j所属集合
        if(iroot!=jroot)//i、j不在同一个集合
          Union(S,iroot,jroot)
        else //i、j原本就在同一集合,即联通
          return 1; 
      }
   return 0;//图中没有环
}

二分查找

int binary_search(int A[],int key,int n){
  int low=0,high=n-1,mid;
  while(low<high){
    mid=(low+high)/2;//取中间位置
    if(A[mid]==key)
      return mid; //查找成功则返回所在位置
    else if(A[mid]>key)
      high=mid-1;//从前半部分继续找
    else 
      low=mid+1;//从后半部分继续找
  }
  return -1;//查找失败返回-1
}
  • 31
    点赞
  • 324
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值