数据结构上机实验(6)

1、实现稀疏矩阵的基本运算

#include <stdio.h>
#include <stdbool.h>
#define N 4
#define MaxSize 100   //矩阵中非零元素最多个数

typedef int ElemType;

typedef struct 
{
    int r;   //行号
    int c;   //列号
    ElemType d;   //元素值   
}TupNode;   //三元组定义

typedef struct
{
    int rows;   // 行数值
    int cols;   // 列数值
    int nums;   // 非零元素个数
    TupNode data[MaxSize];
}TSMatrix;   // 三元组顺序表定义

//产生稀疏矩阵A的三元组表示t
void create_matrix(TSMatrix &t,ElemType A[N][N])
{
    int i,j;
    t.rows=N;
    t.cols=N;
    t.nums=0;   //非零元素个数
    for (i = 0; i < N; i++)
    {
        for (j = 0; j < N; j++)
        {
            if(A[i][j]!=0)
            {
                t.data[t.nums].r=i;   //行号
                t.data[t.nums].c=j;   //列号
                t.data[t.nums].d=A[i][j];   //元素值
                t.nums++;   //非零元素个数增1
            }
        }
    }
}

//输出三元组表示t
void disp_matrix(TSMatrix t)
{
    int i;
    if (t.nums<=0)
        return;
    printf("\t%d\t%d\t%d\n", t.rows, t.cols, t.nums);   //行数,列数,非零元素个数 
    printf("\t------------------\n");
    for (i = 0; i < t.nums; i++)
    {
        printf("\t%d\t%d\t%d\n", t.data[i].r, t.data[i].c, t.data[i].d);
    }
}

//求三元组表示t的转置矩阵T
void tran_matrix(TSMatrix t,TSMatrix &T)
{
    int p,v;
    int q=0;   //q为T.data的下标
    T.rows=t.cols;
    T.cols=t.rows;
    T.nums=t.nums;
    if(t.nums!=0)
    {
        for(v=0;v<t.cols;v++)   //T.data[q]中的记录以c域的次序排列
        {
            for(p=0;p<t.nums;p++)   //p为t.data的下标
            {
                if (t.data[p].c==v)
                {
                    T.data[q].r=t.data[p].c;   //转置矩阵的行号
                    T.data[q].c=t.data[p].r;   //转置矩阵的列号
                    T.data[q].d=t.data[p].d;   //转置矩阵的元素值
                    q++;
                }
            }
        }
    }
}

//求c=a+b
bool matrix_add(TSMatrix a, TSMatrix b, TSMatrix &c)
{
    int i = 0;   //a中非零元素个数索引
    int j = 0;   //b中非零元素个数索引
    int k = 0;   //c中非零元素个数
    ElemType v;
    if(a.rows!=b.rows||a.cols!=b.cols)   //这样不能相加
        return false;

    //c的行列数与a的相同
    c.rows=a.rows;
    c.cols=a.cols;
    while(i<a.nums&&j<b.nums)   
    {
        if(a.data[i].r==b.data[j].r)   //a元素的行号等于b元素的行号
        {
            if(a.data[i].c<b.data[j].c)   //a元素的列号小于b元素的列号
            {
                //将a中元素加到c
                c.data[k].r=a.data[i].r;
                c.data[k].c=a.data[i].c;
                c.data[k].d=a.data[i].d;
                k++;
                i++;
            }
            else if(a.data[i].c>b.data[j].c)   //a元素的列号大于b元素的列号
            {
                //将b中元素加到c
                c.data[k].r = b.data[j].r;
                c.data[k].c = b.data[j].c;
                c.data[k].d = b.data[j].d;
                k++;
                j++;
            }
            else   //a元素的列号等于b元素的列号
            {
                v = a.data[i].d + b.data[j].d;
                if(v != 0)   //只将不为0的结果添加到c中
                {
                    c.data[k].r = a.data[i].r;
                    c.data[k].c = a.data[i].c;
                    c.data[k].d = v;
                    k++;
                }
                i++;
                j++;
            }
        }
        else if(a.data[i].r < b.data[j].r)   //a元素的行号小于b元素的行号
        {
            //将a中元素加到c
            c.data[k].r = a.data[i].r;
            c.data[k].c = a.data[i].c;
            c.data[k].d = a.data[i].d;
            k++;
            i++;
        }
        else   //a元素的行号大于b元素的行号
        {
            //将b中元素加到c
            c.data[k].r = b.data[j].r;
            c.data[k].c = b.data[j].c;
            c.data[k].d = b.data[j].d;
            k++;
            j++;
        }
        c.nums=k;
    }
    return true;
}

//获取三元组t表示的A[i][j]值
int get_value(TSMatrix t,int i,int j)
{
    int k=0;
    while(k<t.nums&&(t.data[k].r!=i||t.data[k].c!=j))
        k++;
    if(k<t.nums)
        return t.data[k].d;
    else
        return 0;
}

//求c=a*b
bool matrix_mul(TSMatrix a,TSMatrix b,TSMatrix &c)
{
    int i;
    int j;
    int k;
    int p = 0; // 矩阵c的非零元素个数
    ElemType s;
    if(a.cols != b.rows)   //a的列数不等于b的行数时不能进行乘法运算
        return false;
    for(i=0;i<a.rows;i++)   //矩阵c的行数
    {
        for(j=0;j<b.cols;j++)   //矩阵c的列数
        {
            s=0;
            for(k=0;k<a.cols;k++)
            {
                s=s+get_value(a,i,k)*get_value(b,k,j);   //求三元组元素
            }
            if(s!=0)
            {
                c.data[p].r = i;   //三元组元素的行号
                c.data[p].c = j;   //三元组元素的列号
                c.data[p].d = s;   //三元组元素的元素值
                p++;
            }
        }
    }
    c.rows = a.rows;
    c.cols = b.cols;
    c.nums = p; // 矩阵c的非零元素个数
    return true;
}

int main()
{
    ElemType a1[N][N] = {
        {1, 0, 3, 0},
        {0, 1, 0, 0},
        {0, 0, 1, 0},
        {0, 0, 1, 1}
    };
    ElemType b1[N][N] = {
        {3, 0, 0, 0},
        {0, 4, 0, 0},
        {0, 0, 1, 0},
        {0, 0, 0, 2}
    };
    TSMatrix a, b, c;

    create_matrix(a, a1);
    create_matrix(b, b1);
    printf("a的三元组:\n");
    disp_matrix(a);
    printf("b的三元组:\n");
    disp_matrix(b);
    printf("a转置为c\n");
    tran_matrix(a, c);
    printf("c的三元组:\n");
    disp_matrix(c);

    printf("c=a+b\n");
    matrix_add(a, b, c);
    printf("c的三元组:\n");
    disp_matrix(c);

    printf("c=a*b\n");
    matrix_mul(a, b, c);
    printf("c的三元组:\n");
    disp_matrix(c);
}

2、实现广义表的基本运算

#include <stdio.h>
#include <malloc.h>

typedef struct lnode
{
    int tag; //结点类型标识,tag为公共部分,只能为1和0,1代表表结点,0代表原子结点
    union
    {
        char data;   //原子结点的值域
        struct lnode *sublist;   //表结点的表头的表头指针
    }val;
    struct lnode *link; // 指向下一个元素
}GLNode; // 声明广义表结点类型

//返回由括号表示法表示s的广义表链式存储结构(递归方法),字符串变广义表 
GLNode *create_gl(char *&s)
{
    GLNode *g;
    char ch = *s++; // 取一个字符

    if(ch != '\0') // 串未结束判断
    {
        g = (GLNode *)malloc(sizeof(GLNode)); // 创建一个新结点
        if(ch == '(') // 当前字符为左括号时
        {
            g->tag = 1; // 新结点作为表头结点
            g->val.sublist = create_gl(s); // 递归构造子表并链到表头结点
        }
        else if(ch == ')') // 遇到右括号字符,g设置为空
        {
            g = NULL;
        }
        else if(ch == '#') // 遇到#字符,表示空表
        {
            g->val.sublist = NULL;
        }
        else // 为原子字符
        {
            g->tag = 0; // 新结点作为原子结点
            g->val.data = ch;
        }
    }
    else // 串结束,g设置为空
    {
        g = NULL;
    }

    ch = *s++; // 取下一个字符
    if(g != NULL) // 串未结束,继续构造兄弟结点
    {
        if(ch == ',') // 当前字符为逗号
        {
            g->link = create_gl(s); // 递归构造兄弟结点
        }
        else // 没有兄弟了,将兄弟指针设置为NULL
        {
            g->link = NULL;
        }
    }

    return g; // 返回广义表g
}

//输出广义表g
void disp_gl(GLNode *g)
{
    if(g != NULL) // 表非空判断
    {
        if(g->tag == 0) // g的元素为原子时
            printf("%c", g->val.data); // 输出原子值
        else // g的元素为子表时
        {
            printf("(");
            if(g->val.sublist == NULL) // 为空表时
                printf("#");
            else    // 为非空子表时
                disp_gl(g->val.sublist); // 递归输出子表
            printf(")");
        }
        if(g->link != NULL)
        {
            printf(",");
            disp_gl(g->link); // 递归输出g的兄弟
        }
    }
}

//求广义表g的长度
int gl_length(GLNode *g)
{
    int n = 0;

    g = g->val.sublist; // g指向广义表的第一个元素
    while(g != NULL)
    {
        n++;
        g = g->link;
    }

    return n;
}

//求广义表g的深度
int gl_depth(GLNode *g)
{
    int max_dep = 0;
    int dep;

    if(g->tag == 0)
        return 0;
    g = g->val.sublist; // g指向第一个元素
    if(g == NULL) // 为空表时返回1
        return 1;
    while(g != NULL) // 遍历表中的每一个元素
    {
        if(g->tag == 1) // 元素为子表的情况
        {
            dep = gl_depth(g); // 递归调用求出子表的深度
            if(dep > max_dep)
                max_dep = dep; // max_dep为同一层所求过的子表中深度的最大值
        }
        g = g->link; // g指向下一个元素
    }

    return (max_dep + 1); // 返回表的深度
}

//求广义表g的最大原子
char gl_max_atom(GLNode *g)
{
    char max1, max2;

    if(g != NULL)
    {
        if(g->tag == 0)
        {
            max1 = gl_max_atom(g->link);
            return (g->val.data > max1 ? g->val.data : max1);
        }
        else
        {
            max1 = gl_max_atom(g->val.sublist);
            max2 = gl_max_atom(g->link);
            return (max1 > max2 ? max1 : max2);
        }
    }
    else
        return 0;
}

//销毁广义表g
void destroy_gl(GLNode *&g)
{
    GLNode *g1, *g2;

    g1 = g->val.sublist; // g1指向广义表的第一个元素
    while(g1 != NULL) // 遍历所有元素
    {
        if(g1->tag == 0) // 若为原子结点
        {
            g2 = g1->link; // g2临时保存兄弟结点
            free(g1); // 释放g1所指原子结点
            g1 = g2; // g1指向后继兄弟结点
        }
        else // 若为子表
        {
            g2 = g1->link; // g2临时保存兄弟结点
            destroy_gl(g1); // 递归释放g1所指子表的空间
            g1 = g2; // g1指向后继兄弟结点
        }
    }
    free(g); // 释放头结点空间
}

int main()
{
    GLNode *g;
    char *str = "(b,(b,a,(#),d),((a,b),c,((#))))";

    g = create_gl(str);
    printf("广义表g:");
    disp_gl(g);
    printf("\n");
    printf("广义表g的长度:%d\n", gl_length(g));
    printf("广义表g的深度:%d\n", gl_depth(g));
    printf("广义表g的最大原子:%c\n", gl_max_atom(g));
    destroy_gl(g);
}

3、求5×5阶螺旋矩阵

#include <stdio.h>
#define MAX_LEN 10

/**
*   学习于CSDN作者-静能生悟
*   螺旋方阵:
*       是指对任意给定的N,将1到N×N的数字从左上角第1个格子开始,
*   按顺时针螺旋方向顺序填入N×N的方阵里。
*   以N=5为例
*       1  2  3  4  5
*       16 17 18 19 6
*       15 24 25 20 7
*       14 23 22 21 8
*       13 12 11 10 9
*   算法思路:
*       以前做Java题遇见过,主要在于如何表达一圈上的数字,最简单用二阶模拟。
*       用二维数组a存放n阶螺旋方阵。偶数阶螺旋方阵共有m(m=n/2)圈,
*   奇数阶螺旋方阵共有m(m=[n/2]+1)圈,对于第i(i从0到m-1共执行m次)圈
*   循环,产生该圈上横行的数字,产生该圈右竖行的数字,产生该圈下
*   横行的数字,产生该圈左竖行的数字。最后输出该方阵。
*/
void helix_matrix(int a[MAX_LEN][MAX_LEN], int n)
{
    int m;   // 圈数
    int i;
    int j;
    int k = 0;

    if(n % 2 == 0)   //偶数阶螺旋方阵
        m = n / 2;
    else   //奇数阶螺旋方阵
        m = n / 2 + 1;
    for(i = 0; i < m; i++)
    {
        //产生该圈上横行的数字
        for(j = i; j < n - i; j++)
        {
            k++;
            a[i][j] = k;
        }
        //产生该圈右竖行的数字
        for(j = i + 1; j < n - i; j++)
        {
            k++;
            a[j][n - i - 1] = k;
        }
        //产生该圈下横行的数字
        for(j = n - i - 2; j >= i; j--)
        {
            k++;
            a[n - i - 1][j] = k;
        }
        //产生该圈左竖行的数字
        for(j = n - i - 2; j >= i + 1; j--)
        {
            k++;
            a[j][i] = k;
        }
    }
}

int main()
{
    int n, i, j;
    int a[MAX_LEN][MAX_LEN];

    printf("输入n(n<10):");
    scanf("%d", &n);
    helix_matrix(a, n);
    printf("%d阶数字方阵如下:\n", n);

    for(i = 0; i < n; i++)
    {
        for(j = 0; j < n; j++)
        {
            printf("%4d", a[i][j]);
        }
        printf("\n");
    }
}

4、求一个矩阵的马鞍点

#include <stdio.h>
#include <stdbool.h>
#define M 3
#define N 3

/**
*   马鞍点:行中最小元素,列中最大元素 
*   算法思路:
*       先求出每行的最小值元素,放入数组min[M]中,再求出每列的最大值元素,放入数组max[N]中,
*   若某元素既在min[i]中,又在max[j]中,则该元素A[i][j]是马鞍点,找出所有这样的元素,也就找
*   到了所有马鞍点。
*/
void min_max(int A[M][N])
{
    int i, j;
    bool have = false;
    int min_row[M], max_col[N];

//每行的最小值元素放入min_row[0,1,...,M-1]中
    for(i = 0; i < M; i++)
    {
        min_row[i] = A[i][0];   //假设第i行第0列的元素为第i行的最小值元素
        for(j = 1; j < N; j++)
        {
            if(A[i][j] < min_row[i])
            {
                min_row[i] = A[i][j];
            }
        }
    }
//每列的最大值元素,放入max_col[0,1,...,N-1]中
    for(j = 0; j < N; j++)
    {
        max_col[j] = A[0][j];   //假设第0行第j列的元素为第j列的最大值元素
        for(i = 1; i < M; i++)
        {
            if(A[i][j] > max_col[j])
            {
                max_col[j] = A[i][j];
            }
        }
    }
//判断是否为马鞍点
    for(i = 0; i < M; i++)
    {
        for(j = 0; j < N; j++)
        {
            if(min_row[i] == max_col[j])
            {
                printf("  A[%d][%d] = %d\n", i, j, A[i][j]);
                have = true;
            }
        }
    }
    if(!have)
        printf("没有马鞍点\n");
}

int main()
{
    int i, j;
    //定义二维数组并初始化 
    int A[M][N] = {
        {9,  7 ,  6},
        {20, 26, 22},
        {28, 36, 25}
    };
    //打印A 
    printf("A矩阵:\n");
    for(i = 0; i < M; i++)
    {
        for(j = 0; j < N; j++)
            printf("%4d", A[i][j]);
        printf("\n");
    }
    //打印马鞍点 
    printf("A矩阵中的马鞍点:\n");
    min_max(A);
}

5、求两个对称矩阵之和与乘积

#include <stdio.h>
#define N 4
#define M 10   // 4*4/2+2 

/**
*   对称矩阵M的第i行和第j列的元素的数据存储在一维数组a中的位置k的计算公式:
*   1、当i大于或等于j时,k = (i * (i + 1)) / 2 + j (下三角)
*   2、当i小于j时,k = (j * (j + 1)) / 2 + i (上三角)
*
*/

//返回压缩存储a中a[i][j]的值
int value(int a[], int i, int j)
{
    if(i >= j)
        return a[(i * (i + 1)) / 2 + j];
    else
        return a[(j * (j + 1)) / 2 + i];
}

//求压缩存储a和b的和
void madd(int a[], int b[], int c[][N])
{
    int i, j;

    for(i = 0; i < N; i++)
    {
        for(j = 0; j < N; j++)
        {
            c[i][j] = value(a, i, j) + value(b, i, j);
        }
    }
}

//求压缩存储a和b的乘积
void mult(int a[], int b[], int c[][N])
{
    int i, j, k, sum;

    for(i = 0; i < N; i++)
    {
        for(j = 0; j < N; j++)
        {
            sum = 0;
            for(k = 0; k < N; k++)
            {
                sum = sum + value(a, i, k) * value(b, k, j);
            }
            c[i][j] = sum;
        }
    }
}

//输出压缩存储a
void disp1(int a[])
{
    int i, j;

    for(i = 0; i < N; i++)
    {
        for(j = 0; j < N; j++)
        {
            printf("%4d", value(a, i, j));
        }
        printf("\n");
    }
}

//输出对称矩阵c
static void disp2(int c[][N])
{
    int i, j;

    for(i = 0; i < N; i++)
    {
        for(j = 0; j < N; j++)
        {
            printf("%4d", c[i][j]);
        }
        printf("\n");
    }
}

int main()
{
    int a[M] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};   //对称矩阵压缩存储
    int b[M] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
    int c1[N][N], c2[N][N];

    printf("a矩阵:\n");
    disp1(a);
    printf("b矩阵:\n");
    disp1(b);

    madd(a, b, c1);
    printf("a+b:\n");
    disp2(c1);

    mult(a, b, c2);
    printf("a*b:\n");
    disp2(c2);
}

posted @ 2020-06-03 11:06  我在吃大西瓜呢  阅读(261)  评论(0)    收藏  举报