四川大学874数据结构算法题

2015篇

1.有一个含有 n 个整数的无序数据序列,所有数据元素各不相同,采用整数数组 R[0, n-1] 存储。要求:

(1). 设计一个尽可能高效的算法,输出序列中第 k(1≤k≤n) 小的元素

  • 两种思路:
    1. 建立一个含 k 个元素的小顶堆进行堆排。堆中保留最大的 k 个数,堆顶即为第 k 小元素;
    2. 采用类似快排的轴枢划分策略,每次划分可以确定一个元素位置。当轴枢为第 k 个位置时轴枢值即为第 k 小的元素;

(2). 给出求解过程并分析时间复杂度。

  • 对于方法1:时间复杂度为 \(n*log_2k\)
  • 代码:
    void PrintNumK(int k, int n)
    {
        // 输出第 k 小的数
        // 建立一个长度为 k 的数组堆排序,每次用原数组的下一个元素换掉堆顶最大元素,数组遍历完后堆顶元素就是目标元素;
        int Heap[k+1];
        int i;
        for (i = 0; i < k; i++)  Heap[i+1] = nums[i];
        for (i = k/2; i > 0; i--) BHeapDownAdjust(Heap, i, k);
        for (i = k; i < n; i++)
        {
            if(Heap[1] > nums[i]) Heap[1] = nums[i]; //外部元素比堆顶小时,把堆顶元素换掉  
            else continue;
    
            BHeapDownAdjust(Heap, 1, k);
        }
        printf("%d",Heap[1]);
    }
    
    void BHeapDownAdjust(int Heap[], int l, int h)
    {	//j将Heap[l]为根节点的子树调整为大顶堆
        //Heap[l] 元素的下沉过程
        // l 和 h 为数组调整范围的 低位 和 高位
        int i=l, j=2*l;
        int temp = Heap[i];
        while (j<=h)
        {
            if (j<h && Heap[j]<Heap[j+1]) j++;
            if (temp<Heap[j])
            {
                Heap[i] = Heap[j];
                i = j;		//继续检查下沉的节点是否还需要下沉
                j = 2 * i;
            }
            else break;
        }
        Heap[i] = temp;
    }
    
  • 对于方法2:平均复杂度为O(n)
  • 代码:
    int SNum_k(int *nums, int low, int high, int k)
    {   // 输出第nums中第 k 小的数
        if (low>high) return -1;    // > 而不是>=; =时还需要走一次
        int L = low, H = high;
        int temp = nums[L];
        while(L<H)
        {
            while(L<H && nums[H]>temp) --H;
            nums[L] = nums[H];	
            while(L<H && nums[L]<temp) ++L;	
            nums[H] = nums[L];
        }
        nums[L] = temp;
        if(L==k-1) printf("%d\n ",temp);    //第 k 小的数应在 k-1 的位置
        if(L<k-1) SNum_k(nums, L+1, high, k);
        else SNum_k(nums, low, L-1, k);
    }
    

2.以带有双亲指针的二叉树作为二叉树的存储结构,节点类型如下:

typedef struct node
{
	int data;
	struct node *lchild, *rchild;
    struct node *parent;
}BinTNode;

1.就中序序列的不同情况,简要叙述求中序后继的方法

  • 两种情况:
    1. 没有右孩子,则 后继节点 是第一个以当前节点所在子树为 左子树 的节点;
    2. 有右孩子,后继节点为右子树中最左的节点。

2.编写算法求px所指节点的中序后继节点

  • 代码
      BinNode *InorderNext(BinNode *px)
      {
          if(px == NULL) retuen NULL;
          BinNode *p = px;
          if(px->rchild != NULL)    //有右孩子时
          {
              p = px->rchild;
              while(p->lchild != NULL) p = p->lchild;
              return p;
          }
          else    // 无右孩子时
          {
              while(p->parent->lchild!=p && p->parent!=NULL) p = p->parent;
              return p->parent;
          }
      }
    

3.只使用孩子指针而使用双亲指针,编写算法输出从 root 到 px 的路径;

  • 思路:中序遍历,用栈保存经过的路径
  • 代码:
    void PrintPath(BinNode *root, BinNode *px)
    {
        static int path[maxsize]; // maxsize 为已定义的满足长度的常数
        static int top=0;
        static int flag=1;  // 路径找到标志,
        if(root && flag) return;    // flag为0时,不需要再向下遍历,直接返回
        path[top++] = root->data;
        if(root == px)  // 满足条件
        {
            for(int i = 0; i < top; i++) print("%d ",path[i]);
            flag = 0; //flag 置 0 ,截断遍历
        }
        PrintPath(root->lchild);
        PrintPath(root->rchild);
        top--;
    }
    

2016篇

1. 一个带头节点的单链表(Linklist),结构为[data;next],在不改变链表的情况下,查找链表中倒数第 k (正整数) 个位置上的节点; 查找成功,输出节点的data值,返回1; 否则,只返回0;

  • 1.思想:设置两个指针,第一个指针先走 k 步(若指针指向空了说明 k 非法),指向不包括头节点在内的第k个节点;此时第二个指针指向头节点的下一个(不包含头节点的第一个节点),然后两个指针同步遍历,当第一个指针的 下一个节点 为空时,第二个指针指向的即为倒数第 k 个元素;

  • 2.代码:

      int SearchReNum_K(Linklist *head, int k)
      {   //打印链表倒数第 k 个元素
          Linklist *p1=head, *p2=head->next;
          for(int i=0; i<k ;i++)  // 将 p1 定位到第 K 个节点
          {
              p1 = p1->next;
              if(p1 == NULL) return 0;    // k 值不合法
          }
          while(p1->next != NULL)     // 遍历到 p1 指向尾节点为止
          {
              p1 = p1->next;
              p2 = p2->next;
          }
          print("%d ", p2->data);
          return 1;
      }
    

2. 求带权有向图的最小路径,要求时间复杂度为O((V+E)logK).

  • 思路: 建立一个堆对边按权值进行堆排序,堆内节点为{node;cost},根据cost排序。问题在于排序完成后边在堆中的位置发生了变化,更新权值时如何定位到对应的边的位置,遍历堆查找应该是最坏情况(结果还是遍历了)
  • 时间复杂度:应该还是做不到题目要求,总的遍历次数 E 次,单每次遍历的最大开销应该是堆中在遍历找边的时候 k;
  • 代码:
    typedef struct
    {   //堆节点
        int cost;   //权值
        int vex;    //顶点
    }HeapNode;
    
    void SHeapUpAdjust(HeapNode* Heap, int k)
    {	//小顶堆单个元素的上浮过程,k上浮元素位置
        int i=k, j=k/2;
        HeapNode temp = Heap[k];
        while (j>0)
        {
            if (temp.cost < Heap[j].cost)
            {
                Heap[i] = Heap[j];
                i = j;		//继续检查节点是否还需要上浮
                j = j/2;
            }
            else break;
        }
        Heap[i] = temp;
    }
    
    void SHeapDownAdjust(HeapNode* Heap, int k, int h)
    {   // 小顶堆单个元素的下沉过程,k: 要调整的元素位置;  h: 堆的总长度
        int i = k, j = 2*k;
        HeapNode temp = Heap[i];
        while(j<=h)
        {
            if (j<h && Heap[j].cost > Heap[j+1].cost) j++;
            if (temp.cost > Heap[j].cost)
            {
                Heap[i] = Heap[j];
                i = j;
                j = 2*j;
            }
            else break;
        }
        Heap[i] = temp;
    }
    
    void HeapDijkstra(AGraph *G, int v)
    {	
        int dist[maxsize], path[maxsize], isJoin[maxsize];
        int num = 0; //堆中有效节点个数
        int pos; //定位节点在堆中的位置
        ArcNode *p;
        HeapNode heap[maxsize+1]; 
        for (int i = 0; i < maxsize+1; i++) //初始化数组
        {
            if (i<maxsize)
            {
                dist[i] = MAX;
                path[i] = -1;
                isJoin[i] = 0;
            }
            heap[i].cost=MAX; // 初始cost为MAX	
            heap[i].vex = -1;	// 节点初始化为-1
        }
        dist[v] = 0;
        path[v] = -1;
        isJoin[v] = 1;
        for (int i = 0; i < G->v - 1; ++i)
        {
            p = G->Adjlist[v].firstarc;
            while (p!=NULL)	// 节点入堆
            {
                if(isJoin[p->vex]) //若边已加入,跳过
                {
                    p=p->nextarc; 
                    continue;
                }
                pos = 0;
                for (int k = 1; k < num+1; k++) //定位节点在heap中的位置
                {
                    if(heap[k].vex==p->vex)
                    {
                        pos = k;
                        break;
                    }
                }
                if(pos && p->cost + dist[v] < heap[pos].cost)//堆中已有p->vex,且v到p->vex + dist[v] 的距离小于现存距离,更新权值
                {
                    heap[pos].cost =  p->cost+dist[v];
                    path[p->vex] = v;	//记录新路径
                }
                if(!pos)	// 堆中无p->vex 点, 有效节点数num+1,在新位置填入新节点
                {
                    heap[++num].vex = p->vex;
                    heap[num].cost = p->cost + dist[v];
                    path[p->vex] = v;
                }
                SHeapUpAdjust(heap, num);	// 堆底上浮
                p=p->nextarc; 
            }
            dist[heap[1].vex] = heap[1].cost;	
            v = heap[1].vex; 	// 以堆顶节点开始下一次
            isJoin[v] = 1;
            heap[1] = heap[num--]; 	//换掉堆顶节点,有效节点数-1
            SHeapDownAdjust(heap, 1, num); 	//堆顶下沉
        }
    }
    

2017篇

1.关于堆,问:

  • 1.存储方式是顺序的还是链接。 顺序
  • 2.最大元素和最小元素在说明位置。 最大:堆顶; 最小:叶子节点
  • 3.对 n 个元素的建队过程中,最多和最少进行多少次比较;
    • 最少:堆原始有序,从 n/2 开始比较; 若 n 为奇数,共 \(\frac{n}{2}*2 = n-1\) 次;若 n 为偶数,最后一个节点只比较一次,共 \(\frac{n}{2}*2-1 = n-1\) 次。
    • 最多:假设堆是完全二叉树;树高 \(h = log_2n+1\), 从 h-1 层开始比较
      • 讨论最多情况,第\(h-1\) 层 每个节点 只需与下一层比较,每个比较2次,共 \(2*2^{h-2}*1\)
      • \(h-2\) 层除了和下一层比较之外,下坠后 还需和下层继续比较, 共 \(2*2^{h-3}*2\)
      • 则第 k 层的元素,最多需要比较的次数为 \(2*2^{k-1}*(h-k)\)
      • 总次数为\(\sum_{k=1}^{h-1}(2*2^{k-1}*(h-k))\) = \(2^{h+1}-2(h+1)\)

2. 两个非空带头节点的增序单链表 ha,hb,求两个链表的交集并将结果存放与 hc 中;要求不能破坏原来的链表。节点结构为:

typedef struct Node
{
	int data;
	struct Node *next;
}Node, *LinkList;
  • 设计一个高效算法并给出时间复杂度
    Node *Intersection(LinkList ha, LinkList hb)
    {   // 返回两个链表的交集, 带头节点的链表
        LinkList hc = (Node *)malloc(sizeof(Node));
        Node *pa = ha->next, *pb = hb->next, *p, *pre;
        hc->next = NULL;
        while(pa && pb)
        {
            if(pa->data == pb->data)
            {
                p = (Node *)malloc(sizeof(Node)));
                p->data = pa->data;
                p->next = NULL;
                if(hc->next == NULL)    //第一个节点特殊处理
                {
                    hc->next = p;
                    pre = p;
                }
                else    // 后续节点尾插法
                {
                    pre->next = p;
                    pre = p;
                }
            }
            else if(pa->data > pb->data) pb = pb->next;    // 较小的节点向后走
            else pa = pa->next;
        }
        return hc;
    }
    
    

3 设计一个算法判断 无向图 中是否有环

  • 思路1: 统计图中 边的个数n 和 节点的个数m,若n>m-1 则说明存在环路
  • 代码:
    int DetectLoop(AGraph *G, int v)
    {
        static int visit[maxsize];
        static int edge, vertex;
        ArcNode *p = G->Adjlist[v].firstarc;
        visit[v] = 1;
        vertex++;	// 记顶点
        while(p!=NULL)
        {
            edge++;	//记边
            if(visit[p->vex]==0)
                DetectLoop(G, p->vex);
            p = p->nextarc;
        }
        if(edge/2 >= vertex) 
        {
            printf("YES");
            return 1;
        }
        return 0;
    }
    
  • 思路2:深度遍历,需要将上一个过来的节点标记
  • 代码:
    int DetectLoop2(AGraph *G, int v, int pre)
    {   //pre:上一个节点
        static int visit[maxsize];
        static int flag=0;    // 环标记
        
        if(flag) return flag;
        ArcNode *p = G->Adjlist[v].firstarc;
        visit[v] = 1;
        while(p!=NULL)
        {
            if(p->vex!=pre && visit[p->vex]) flag = 1;  //找到环路
            if(!visit[p->vex]) DetectLoop2(G, p->vex, v);
            p = p->nextarc;
        }
        return flag;
    }
    

扩展.设计一个算法判断 有向图 中是否有环

  • 思路:回溯深度遍历,若一个节点在深度遍历完成之前再次回到了自己,说明存在环路;
    与普通深度遍历的区别:常规深度遍历会在访问一个节点后将其标记为已访问,下次遇到时不会访问它;
    而回溯深度遍历增加一个标志 标记本轮遍历的节点。若某个节点在一轮遍历中被访问两次,说明有环;
  • 代码:
    1. 图结构
    typedef struct ArcNode
    {	//边节点
        int vex; //当前边指向的节点信息
        int cost; //边代价
        struct ArcNode *nextarc;	//下一条边
    }ArcNode;
    
    typedef struct VNode
    {	//顶点节点
        int vex;	//顶点数据
        ArcNode *firstarc;	// 顶点出来的第一条边
    }VNode;
    
    typedef struct AGraph
    {
        //邻接表
        VNode Adjlist[maxsize];	//顶点数组
        int v,e; //当前顶点的顶点数和边数
    }AGraph;	
    
    1. 代码
    int DetectCircle(AGraph *G, int v)
    {
        // 基于DFS 检测有向图中是否存在环路;
        static int visit[maxsize];
        static int finished[maxsize];
        static int flag = 0;	//标记位
    
        if (flag) return 1;	//flag 用于对遍历进行截支,满足条件直接返回,不再继续遍历
        ArcNode *p = G->Adjlist[v].firstarc;
        visit[v] = 1;
        finished[v] = 1; // finished[i]=1 表示还在本轮遍历之中,再次访问到自己说明存在环路
        //printf("%d ",v);
        while(p!=NULL)
        {	
            if (finished[p->vex]==1)
            {
                flag=1; 	// 同一个节点被再次访问, 说明存在环路;
                return 1;	// 已检测到回路直接返回;
            }
            if(visit[p->vex]==0)
            {
                DetectCircle(G,p->vex);
                finished[p->vex]=0;
            }
            p = p->nextarc;
        }
        return flag;
    }
    

2018篇

1.有n个顶点的有向图用邻接表表示,写一个算法求顶点 k 的入度

  • 遍历邻接表计数求和, 记邻接表为 Adjlist
  • 代码
    int InDegree(AGraph *G, int k)
    {
        ArcNode *p;
        int sum=0;
        for(int i=0; i< G->n; i++)
        {
            p = G->Adjlist[i].firstarc;
            while(p != NULL)
            {
                if(p->data == k)
                {
                    sum++;
                    break;
                }
                p = p->next;
            }
        }
        return sum;
    }
    
    

2.递归求一颗树中各个节点的平衡因子

  • 深度遍历:一个节点的平衡因子等于 左子树高度 减去 右子树高度;
  • 节点结构{ lchild; rchild; bf; data}
  • 代码:
    int BalanceNum(BinNode *root)
    {
        if(root==NULL) return 0;
        int LD, RD;
    
        LD = BalanceNum(root->lchlid);
        RD = BalanceNum(root->rchlid);
        root->bf = LD - RD;
        return (LD>RD)?(LD+1):(RD+1); //返回较大的 + 1 作为上一层的树高
    }
    

2019篇

1.深度优先遍历实现有向图的拓扑排序

  • 思路:在遍历退出的时候记录节点,可以得到一个逆拓扑排序序列,逆序输出即可得到一个拓扑排序
  • 代码:
    TopoSort(Grapg *G, int v)
    {
        static int topo[maxsize];
        static int top = 0;
        static int visit[maxsize];
        ArcNode *p = G->Adjlist[v].firstarc;
        visit[v] = 1;
        while( p!= NULL)
        {
            if(!visit[p->vex]) 
                TopoSort(G, p->vex);
            p = p->nextarc;
        }
        topo[top++] = v;	//递归退出节点时节点入栈,栈序列为逆拓扑序列
    
        if(top == maxsize)  //逆序输出
            for(int i=top-1; i>=0; i--) print("%d ", topo[i]);
    
    }
    

2.用单链表表示任意长度的整数,每个节点存储一位整数。实现两个正整数的减法操作;

  • 代码
    Node *Minus(Node *LA, Node *LB)
    {
        //LA - LB
        LA = Reverse(LA);   //反转数组 ,从地位到高位依次相减
        LB = Reverse(LB);
        int carry=0;    //carry为借位,不够减的时候需要向下一位借位
        int i;
        Node *pla = LA;
        Node *la = LA->next;
        Node *lb = LB->next;
        while (la && lb)
        {
            if (la->d < lb->d)  //如果不够减产生借位
            {
                la->d = la->d - lb->d + 10 - carry;
                carry = 1;
            }
            else
            {
                la->d = la->d - lb->d - carry;
                carry = 0;
            }
            la = la->next;
            lb = lb->next;
            pla = pla->next;
        }
        if (la==NULL) //a 的位数比 b 少的时候, 
        {
            pla->next = lb;
            while (lb!=NULL)
            {
                lb->d = 0 - lb->d + 10 - carry;
                carry = 1;
                lb = lb->next;
            }
        }
        else    //a 的位数比 b 多的时候,
        {
            while (la!=NULL && carry)
            {
                if(la->d==0) 
                {
                    la->d = la->d + 10 - carry;
                }
                else 
                {
                    la->d = la->d - carry;
                    carry=0;
                }
                la = la->next;
            }
        }
        la = LA->next;
        if (carry==1)  //最后 carry 为 1 的话说明最高位仍产生借位 ,结果为负数
        {
            /*  
            比如 123 - 456 = -333,反转后对应位相减结果为 321 - 654 = 766;
            carry=1,表示最终结果是负数;处理方法是对所有位 9-x;最后第一位再 +1;
            9-7+1=3; 9-6=3; 9-6=3
            结果为 -333;
            */
            while (la!=NULL)
            {
                la->d = 9 - la->d;     //用 9 减所有位
                la = la->next;
            }
            LA->next->d++; //个位数修正
        }
    
        la = LA;
        la = Reverse(la);
        while (la->next->d == 0)    // 将头节点定位到第一个非 0 元素前面,结果为0要特殊考虑
            {
                if(la->next->next!=NULL) la = la->next; 
                else   
                {
                    la->next->d = 0;
                    break;
                }
            }
        if (carry==1)   // 用头节点标记正负
            la->d = -1;
        else la->d = 1;
    
        Show(la); 
        //返回结果链表头节点,头节点为-1表示结果为负数,1表示结果非负;
        return la;
    }
    

2020篇

1.二叉树, 从左到右输出第 k 层的节点;

  • 思路:层次遍历, 队列(front)进行删除操作,(rear)进行插入操作
  • 代码:
    void K_Floor(BinNode *root, int k)
    {   // 输出第 k 层的节点, 记 root 为第一层
        int queue[maxsize];     // 队列结构 {node, n} ,n标记node所在层
        int le;
        int front=0, rear=0;    // 空时rear==front,不空时front指向第一个,rear指向最后一个的后一个位置
        BinNode *p;
        queue[rear++].node = root; 
        queue[front].n =1;
    
        while(front!=rear)
        {
            p = queue[front].node;
            le = queue[front].n;
            front = (front+1)%maxsize;
            if(le < k) //到 k-1 层为止, 恰好 k 层可以全部入队
            {
                if(p->lchild != NULL)   // 左孩子入队
                {
                    queue[rear].node = p->lchild;
                    queue[rear].n = ++le;   // 层数+1
                    rear = (rear+1)%maxsize;
                }
                if(p->rchild != NULL)   // 右孩子入队
                {
                    queue[rear].node = p->rchild;
                    queue[rear].n = ++le;   // 层数+1
                    rear = (rear+1)%maxsize;
                }
            }
            if(le = k) print("%d ", p->data);
        }
    }
    
    

2.堆排序,删除p位置的元素,重排小根堆;所谓删除,应该是把p位置的数移到数组最后

  • 小根堆排序
  • 代码
    void SheapDownAdjust(int *heap, ,int k, int h)
    {
        int i=k, j=2*k;
        int temp = heap[i]
        while(j<=h)
        {
            if(j< h && heap[j]>heap[j+1]) j++;  //取较小的
            if(temp>heap[j])
            {
                heap[i] = heap[j];
                i = j;
                j = 2*j;
            }
            else break;
        }
        heap[i] = temp;
    }
    
    void Delet_p(int *heap, int h, int p)
    {
        heap[n] = heap[p];
        for(int i=n/2; i>0; i++) SheapDownAdjust(heap, i, h-1);
    }
    

2021篇

1.设带权有向图用邻接矩阵表示,判断图中是否存在从\(V_i\)\(V_j\)的路径,并计算路径长度。要求给出邻阶矩阵的描述。

  • 思路:从\(V_i\)开始深度遍历,如果在遍历中经过了\(V_j\)节点,则说明存在路径。
  • 代码:
    //
    typedef struct Graph
    {
        Adjlist[maxsize][maxsize];  // 邻接矩阵
        int v,e;    // 顶点数和边数
    } Graph;
    
    int MDFS1(Graph *G, int v, int j)
    {   // 若存在路径,则返回长度。若不存在,则返回-1
        static int visit[maxsize];
        static int d=0;   //记录遍历长度
        static int result=-1;	//记录结果长度
        if(result!=-1) return result; 	//截断遍历, result不为-1时,说明已经找到路径
        if(v == j) result = d;
        d++;
        visit[v] = 1;
        for(int k=0; k<maxsize; k++)
            if(G->Adjlist[v][k] && !visit[k])
                MDFS1(G, k, j);
        d--;
        return result;
    }
    

2.中缀表达式转后缀表达式 可能出现的运算符 + - * / ^ ( )

  • 思路:用两个栈,一个栈存放操作符, 一个存放后缀表达式结果
    • 遇到数字直接入结果栈
    • 遇到操作符,直接入操作符栈,遇到 则弹出上一个括号前的全部操作符入结果栈;遇到其他操作符时,若操作符栈为空,直接入栈;若不空,则需和栈顶符比较优先级,栈顶符优先级高或相同时将栈顶符弹出入结果栈,否则之间把现操作符压栈;
    • 代码
      // 辅助函数
      int isop(char c)
      {
          // c 是操作符返回 1, 否则返回 0;
          return (c=='+'||c=='-'||c=='*'||c=='/'||c=='^')?(1):(0);
      }
      
      int comop(char op1, char op2)
      {
          //如果 op2 操作符比 op1 操作符优先级高或相等,返回 1 ,否则返回 0;
          //if (op2=='(' && op1=='(') return 1;
          if (op2=='(') return 0; //遇到栈中的括号,返回 0 不允许计算
          if (op1=='^') return 0;
          if (op1=='+' || op1=='-') return 1;
          if (op2=='*' || op2=='/' || op2=='^') return 1;
          return 0;
      }
      //
      void IntoRear(char *arr, int n)
      {
          char opstack[n]; //操作符栈
          char restack[n]; //结果栈
          int optop=-1, retop=-1;
          for(int i=0; i<n-1; i++)	//字符串结尾有个空符
              {
              if(arr[i]== '(' )   opstack[++optop] = arr[i];
              else if(arr[i]== ')')
              {
                  while(opstack[optop]!='(')
                      restack[++retop] = opstack[optop--];
                  optop--;    //跳过当前这个 '('
              }
              else if(!isop(arr[i])) restack[++retop] = arr[i];   //数字直接入栈
              else    // 操作符时
              {
                  if(optop == -1) opstack[++optop] = arr[i];  //栈空,直接入栈
                  else 
                  {   // comop(op1, op2), 当 op2 的优先级高于 op1 时返回 1, 否则返回 0;
                      // opstack[optop] 栈顶的符号可能为括号,此时直接入操作符栈
                      if(opstack[optop]=='(' || comop(opstack[optop], arr[i])) opstack[++optop] = arr[i];
                      else
                      {
                          restack[++retop] = opstack[optop--];
                          opstack[++optop] = arr[i];
                      } 
                  }
              }
          }
          while(optop!=-1) restack[++retop] = opstack[optop--]; //弹出剩余的
          for (int i = 0; i <= retop; i++) printf("%c ",restack[i]);
      }
      

2022篇

1.随机序列 \(A[a_0...a_{n-1}]\), 设计一个算法使\(a_i\)左边的元素都小于\(a_i\)\(a_i\)右边的元素都大于\(a_i\)

  • 快排划分思想
  • 代码:
    void QuickSort(int *nums, int n)
    {
        int L = 0, H = n-1;
        int temp = nums[L];
        while(L<H)
        {
            while(L<H && nums[H]>temp) --H;
            nums[L] = nums[H];	//此处不能写成nums[L++] = nums[H],因为若本次循环没有比temp小的数,那么有H==L,经过nums[L++] = nums[H] 会导致 L 比 H 大1,指向错误的位置,但nums[L] = nums[H],会有已经确定的a[L]<temp重复判断一次,但结果是正确的。
            while(L<H && nums[L]<temp) ++L;
            nums[H] = nums[L];
        }
        nums[L] = temp;
    } 
    

2.计算一颗树的外部带权路径长度WPl,即根节点到所有叶子的权值之和;

  • 树的结构位 {lchild; rchild; weight}
  • 思路:深度遍历;顺便记录路上权值,遇到叶子节点时累加一次
  • 代码:
    int WPL=0;
    int sum=0;
    void CalWPL(BTree *root)
    {
        if(root==NULL) return;
        sum += root->weight;    //加权值
        if(!root->lchild && !root->rchild) WPL += sum;
        CalWPL(root->lchild);
        CalWPL(root->rchild);
        sum -= root->weight;    //还权值
    }
    
    

总结篇:

  • 以上内容为个人在2022考研复习期间整理出的内容,仅供参考;希望能给到后面考研的朋友一些帮助。

posted @ 2021-12-28 14:48  zzzggb  阅读(438)  评论(0编辑  收藏  举报