【计算机考研】408历年代码大题(2014~2019)

2014年——二叉树

求二叉树的带权路径长度WPL(所有叶结点的带权路径长度之和)

Typedef struct BTNode{
    int weight;
    struct BTNode *left,*right;
}BTNode;

int fun(BTNode *root,int deep){
    int A,B;
    if(root==NULL) return 0;
    if(root->left==NULL && root->right==NULL)
        return (root->wight)*deep;
    A=fun(root->left,deep+1);    //往左走一步,deep就加1
    B=fun(root->right,deep+1);   //往右走一步,deep也加1
    return A+B;
}
void print(BTNode *root){
    fun(root,0);                 //用主函数调用为deep赋初值0
}

2015年——链表

时间上尽可能高效:(空间换时间)虚拟数组

算法思想:利用一个大小为n的数组,用于保存此绝对值是否存在的信息。在遍历单链表时,对任意一步单链表进行如下操作:进行判断这个值代表的标记数组中的值是否存在,

  • 如果存在则删除当前结点;
  • 如果不存在,则讲其标记数组中的值修改为1,代表存在;

遍历完整个单链表之后,上述操作即为题目所求。

typedef struct node{
    int data;
    struct node *link;
}NODE;
Typedef NODE *PNODE;

void fun(PNODE h,int n){
    PNODE p=h,r;
    int m;
    //创建一个长度为n+1的虚拟数组
    int *q=(int*)malloc(sizeof(int)*(n+1));
    //初始化改虚拟数组,把每一位都改为0
    for(int i=0;i<n+1;i++) q[i]=0;
    
    while(p->link!=NULL){
        m=p->link->data>0?p->link->data:-p->link->data;
        //判断该结点的data有无出现过
        if(q[m]==0){      //首次出现
            q[m]==1;
            p=p->link;
        }
        else{
            r=p->link;    //用一个新的结点指向p的next域,即下一结点的地址
            p->link=r->link;
            free(r);
        }
    }
    free(q);    
}

2016年——快排

满足:‘元素个数的差距最小’且‘元素之和的差距最大’

**算法思想:**将最小的└(n/2)┘个元素一起,其他的一起即可(奇数:中间值放右边)

int setPartition(int a[],int n){
    int piovtkey,flag=1,i;  //找到分界线,即把flag置为0
    int k=n/2;
    int low=0,low0=0,high=n-1,high0=n-1;
    int s1=0,s2=0;
    //快排
    while(flag){
        piovtkey=a[low];          //选择数组的第一个元素作为枢轴
        while(low<high){          //基于枢轴对数据进行划分
            while(low<high && a[high]>=pivotkey)--high;
            if(low!=high) a[low]=a[high];
            while(low<high && a[low]<=pivotkey)++low;
            if(low!=high) a[high]=a[low];
        }//end of while(low<high)
        a[low]=piovtkey;
        if(low==k-1)flag=0;       //如果枢轴为第n/2个元素,划分成功
        else{                     //继续划分
            if(low<k-1){
                low0=++low;high=high0;
            }
            else{
                high0=--high;low=low0;
            }
        }
    }
    for(i=0;i<k;i++)s1+=a[i];//对前半部分求和
    for(i=k;i<n;i++)s2+=a[i];//对后半部分求和
    return s2-s1;
}

2017年——树的中序遍历

**算法思想:**利用二叉树的中序遍历,并合理地添加括号:括号的添加其实就是每层递归遍历的左右添加括号即可,但是要注意叶结点(操作数)左右和根节点(最外层)无需添加。

**注:**此算法题若不加deep变量准确添加括号,而是每一步都加也只扣一份;

void BtreeToE(BTree *root){
    BtreeToExp(root,1);             //根的高度为1
}
void BtreeToExp(BTree *root,int deep){
    if(root==NULL)
        return;                           //空结点返回
    else if(root->left==NULL && root->right==NULL)   //若为叶结点
        print("%s",root->data);           //输出操作数,不加括号
    else{
        if(deep>1)print("(");             //若有子表达式则加1层括号
        //中序遍历
        BtreeToExp(root->left,deep+1);
        print("%s",root->data);           //输出操作符
        BtreeToExp(root->left,deep+1);
        print("%s",root->data);           //若有子表达式则加1层括号
    }
}

2018年

给定一个含n(n≥1)个整数的数组,请设计一个在时间上尽可能高效的算法,找出数组中未出现的最小正整数。例如,数组{-5,3,2,3}中未出现的最小正整数是1; 数组{1,2,3}中未出现的最小正整数是4。要求:

(1)给出算法的基本设计思想。

(2)根据设计思想,采用C或C++语言描述算法,关键之处给出注释。

(3)说明你所设计算法的时间复杂度和空间复杂度。

int findMissMin(int A[],int n){
    int i,*B;                        //标记数组
    B=(int*)malloc(sizeof(int)*n);   //分配空间
    memset(B,0,sizeof(int)*n);       //赋初值为0
    for(i=0;i<n;i++)
        if(A[i]>0 && A[i]<=n)        //若A[i的值介于1~n,则标记数组B
            B[A[i]-1]=1;
    for(i=0;i<n;i++)                 //扫描数组B,找到目标值
        if (B[i]==0)break;
    return i+1;                      //返回结果
}

2019年——单链表逆置、合并

**题干:**L=(a1,a2,a3,…an-2,an-1,an)➡️ L’=(a1,an,a2,an-1,a3,an-2,…),S(O)=O(1);

算法思想:

①先找出链表L的中间结点,为此设置两个指针p和q,指针p每次走一步,指针q每次走两步,当指针q到达链尾时,指针p正好在链表的中间结点;

②然后将L的后半段结点原地逆置。

③从单链表前后两段中依次各取一个结点,按要求重排。

typedef struct node{
    int data;
    struct node *next; 
}NODE;
void change_list(NODE *h){
    NODE *p,*q,*r,*s;
    p=q=h;
    //寻找中间结点
    while(q->next!=NULL){
        p=p->next;                //p走一步
        q=q->next;
        if(q->next!=NULL)
            q=q->next;            //q走两步
    }
    q=q->next;                    //p所指结点为中间结点,q为后半段链表的首结点
    p->next=NULL;                 //将前后两部分结点断开
    //将链表后半段转置
    while(q!=NULL){               //
        r=q->next;                //
        q->next=p->next;          //q->next=NULL
        p->next=q;
        q=r;
    }
    s=h->next;                    //s指向前半段的第一个数据结点,即插入点
    q=p->next;                    //q指向后半段的第一个数据结点
    p->next=NULL; 
    //将链表后半段的结点插入到指定位置
    while(q!=NULL){
        r=q->next;                //r指向后半段的下一个结点
        q->next=s->next;          //将q所指结点插入到s所指结点之后
        s->next=q;
        s=q->next;                //s指向前半段的下一个插入点
        q=r;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值