第3章第1节练习题1 蛇形矩阵

问题描述

蛇形矩阵即使用二维数组完成来回曲折的赋值,举例说明如下所示的形式即为蛇形数组。

算法思想

观察该二维数组,只是可以“人为”的发现它就像一条蛇的形状来回爬行,然而并没有什么卵用,不能明确的站在计算机的角度上来实现这个数组。于是将所有的下标列出来便可以得到下述所述的曲线走势。

然后结合第一张图便可以发现

  • 数字从2~3的过程中,下标行变化范围是0~1;下标列范围是1~0;
  • 数字从4~6的过程中,下标行变化范围是2~0;下标列范围是0~2;
  • 数字从7~10的过程中,下标行变化范围是0~3;下标列范围是3~0;
  • 数字从11~15的过程中,下标行变化范围是4~0;下标列范围是0~4;
  • 数字从16~19的过程中,下标行变化范围是1~4;下标列范围是4~1;
  • 数字从20~22的过程中,下标行变化范围是4~2;下标列范围是2~4;
  • 数字从23~24的过程中,下标行变化范围是3~4;下标列范围是4~3;

如果再仔细一点就可以发现,每次轮回(数字从左下到右上或从右上到左下的递增)的过程中,其行下标与列下标之和是不变的。为了清楚的说明这一点,参考下图。

每条红线所标识的每个下标之和不变,比如下标从01变为10(注:这里的10意思是(1, 0)即元素下标,后面同理),其行下标与列下标之和为1;在比如下标从20变为11在变为02的过程中,行下标与列下标之和为2;依次类推。为了方便表示,沿主对角线方向画一条绿色的线,该线与红线的交点表示每条红线中的每个元素所代表的行下标与列下标之和。

使用(i,j)表示每个元素的下标,使用k表示沿绿线方向的每个元素的下标之和,这样每个元素的下标便可以表示为(i,k-i);

但应该注意到副对角线上下部分下标的变化方式不同,在副对角线上半部分,行下标和列下标最小值为0,最大值依次递增;而副对角线下半部分,行下标和列下标的最大值为4,而最小值递增。

算法描述

void SnackArray(int A[][N]){
    int cnt=0;
    //副对角线上半部分
    for(int k=0;k!=N;k++){
        if(k%2==0){
            //从左下到右上
            for(int i=k;i>=0;i--){
                A[i][k-i]=++cnt;
            }
        }else{
            //从右上到左下
            for(int i=0;i<=k;i++){
                A[i][k-i]=++cnt;
            }
        }
    }
    //副对角线下半部分
    for(int k=N;k<2*N-1;k++){
        if(k%2==0){
            //从左下到右上
            for(int i=N-1;i>=k-N+1;i--){
                A[i][k-i]=++cnt;
            }
        }else{
            //从右上到左下
            for(int i=k-N+1;i<=N-1;i++){
                A[i][k-i]=++cnt;
            }
        }
    }
}

具体代码见附件。


附件

#include<stdio.h>
#define N 5

void SnackArray(int (*)[N]);
void Show(int (*)[N]);

int main(int argc,char* argv[]){
    int Arry[N][N]={{0}};
    SnackArray(Arry);
    Show(Arry);
    return 0;
}

//蛇形数组赋值
void SnackArray(int A[][N]){
    int cnt=0;
    for(int k=0;k!=N;k++){
        if(k%2==0){
            for(int i=k;i>=0;i--){
                A[i][k-i]=++cnt;
            }
        }else{
            for(int i=0;i<=k;i++){
                A[i][k-i]=++cnt;
            }
        }
    }
    for(int k=N;k<2*N-1;k++){
        if(k%2==0){
            for(int i=N-1;i>=k-N+1;i--){
                A[i][k-i]=++cnt;
            }
        }else{
            for(int i=k-N+1;i<=N-1;i++){
                A[i][k-i]=++cnt;
            }
        }
    }
}

//打印蛇形数组
void Show(int A[][N]){
    for(int i=0;i!=N;i++){
        for(int j=0;j!=N;j++){
            printf("%5d",A[i][j]);
            if(j==N-1){
                printf("\n");
            }
        }
    }
}
时间: 2024-10-12 23:44:38

第3章第1节练习题1 蛇形矩阵的相关文章

第4章第1节练习题9 反向层次遍历算法

问题描述 试给出二叉树的自下而上,从右到左的层次遍历算法 算法思想 一般的二叉树层次遍历算法是自上向下,从左到右的遍历,这里的遍历顺序恰好相反,而运用栈先进后出的特点实现顺序的反转. 因此可以考虑在原来的层次遍历算法的基础上加上栈的基本操作.在出队的同时将各节点入栈,在所有的节点全部入栈后,依次出栈访问便可解决该问题. 算法描述 void InLevelOrder(BiTNode* T){ BiTNode *p=T; SqQueue Q; InitQueue(&Q); SqStack S; In

第4章第1节练习题6 二叉树叶子节点链接成单链表

问题描述 设计一个算法,将二叉树的叶子节点按从左到右的顺序连成一个单链表,表头指针为head.链接时用叶子节点的右指针来存放单链表指针. 算法思想 题目要求将叶子节点按自左向右的次序连接成一个单链表,因此很容易考虑到的便是将整棵二叉树按照先序或中序或后序的方式遍历一次. 在遍历的过程中对叶子节点单独判断,如果是叶子节点,则将其做一个标识(比如用额外的指针指向该节点),接着遍历下一个叶子节点,遍历到另一个叶子节点后,然后让已被标识的叶子节点的右孩子指向该节点,依次类推便可以实现将叶子节点连接成单链

第1章第2节练习题3 删除最小值结点

问题描写叙述 试编写在带头结点的单链表L中删除一个最小值结点的高效算法(如果最小值结点是唯一的) 算法思想 在链表中删除最小值的前提是必须找到最小值元素是哪个结点,因此设置指针p对全部结点进行遍历,使用指针min指向最小值结点.可是由于涉及到删除操作,明显在仅仅有指针min和指针p的条件下删除操作是极为不方便的. 若单纯的删除指针p指向的结点会造成断链.若採用2.5.2删除自身结点的方法,又会出现多次赋值操作. 因此直接引入两个分别指向其前驱结点的指针pre和premin,如此.删除操作过程会更

第1章第2节练习题4 删除指定区间结点

问题描述 设一个带表头结点的单链表中所有元素结点的数据值无序,试编写一个函数,删除表中所有其值在给定值s与t之间(包含s和t,要求s<t)的所有结点 算法思想 因为链表逻辑上无序,删除指定区间结点的前提是找到这些指定区间结点.因此从头节点开始对整个链表进行一次遍历,若找到满足题意的结点,删除即可. 算法描述 void Delts(LNode* head, ElemType t, ElemType s) { LNode *pre=head; LNode *p=head->next; while(

第4章第1节练习题10 判断某二叉树是否为完全二叉树

问题描述 试写一算法,完成判定某二叉树是否为完全二叉树的功能 算法思想 根据完全二叉树的定义,具有n个节点的完全二叉树与满二叉树中的编号从1~n的节点一一对应,可以考虑使用层次遍历的思想来实现. 将所有节点入队(包括空节点).当遇到空节点时,查看其后是否还有不为空的节点:如果没有,则为完全二叉树:如果有,则不是完全二叉树: 算法描述 int IsComplete(BiTNode* T){ SqQueue Q; InitQueue(&Q); BiTNode *p=T; EnQueue(&Q,

第2章第2节练习题3 使用队列模拟渡口管理

问题描写叙述 汽车轮渡口,过江渡船每次能载10辆车过江.过江车分为客车和货车类.上渡船有例如以下规定: 1).同类车先到先上船. 2).客车先于货车上渡船,其每上4辆客车,才同意放上一辆货车: 3).若等待客车不足4辆.则以货车取代: 4).若无货车等待,同意客车都上船. 试设计一个算法模拟渡口管理 算法思想 经过分析,发现此题实际上就是队列的基本操作,唯一的不同就是在入队的时候,对于顺序进行了限制. 使用队列Q表示每次载渡的车辆,队列Qp表示客车.Qt表示货车队列: 假设Qp中元素足够.则每从

第1章第2节练习题2 非递归删除指定结点

问题描写叙述 在带头结点的单链表L中.删除全部值为x的结点,并释放其空间,假设值为x的结点不唯一,试编写算法实现以上的操作 算法思想 使用指针p指向数据域为x的结点.使用指针pre指向指针p所指结点的前驱结点,从前向后进行遍历.假设指针p指向的结点的数据域为x,则删除.假设指针p指向的结点的数据域不为x,继续向后遍历就可以. 算法描写叙述 void DelNodeX(LNode *head, ElemType x) { LNode *pre=head; LNode *p=head->next;

第4章第1节练习题12 删除以指定节点为根节点的所有子树

问题描述 已知二叉树以二叉链表存储,编写算法完成对于树中每一个元素值为x的节点,删去以它为根的子树,并释放相应空间 算法思想 本题可以分成两个部分来完成.第一步:查找值为x的节点:第二步:删除以值为x的节点为根节点的所有子树: 因为删除的是x的所有子树,因此遍历方式应该选择自上而下的遍历方式,即先序遍历或层次遍历方式,这里选择层次遍历的方式实现. 删除值为x的节点的所有子树,可以考虑使用递归的方式: 即此时可以认为删除的是以值为x的节点作为根节点的树: 首先删除该树的叶子节点,这样该树的倒数第二

第4章第1节练习题8 打印指定节点的祖先节点

问题描述 在二叉树中查找值为x的节点,试编写算法打印值为x的节点的所有祖先节点,假设值为x的节点不多于一个 算法思想 因为仅仅只是打印祖先节点,可以考虑使用非递归后序遍历的方式来实现. 在非递归后序遍历的方式中,保留在栈中的所有元素(除栈顶外)必然是栈顶的祖先节点,因此只要找到x节点,然后将栈中所有节点出栈便可. 算法描述 void AncestorX(BiTNode* T,ElemType x){ SqStack S; InitStack(&S); BiTNode* p=T; BiTNode*