十字链表法稀疏矩阵的基本操作(C语言)

在十字链表中每一个非0元素可以用一个含5个域的结点表示,其中i,j,e分别表示非0元所在的行、列以及值
向右域right链接同一行中下一个非0元,向下域down链接同一列中下一个非0元 可用两个分别存储行列链表的头指针的一维数组表示
结构如图
在这里插入图片描述
down存放同一列中的下一个非0元的地址
right存放同一行中的下一个非0元的地址
rhead存放OLink的地址,即OLNode地址的地址
malloc rhead结构指针即分配n个OLink的地址

代码实现部分

基本操作有初始化,创建,打印,拷贝域销毁

头文件部分

需要用到的头文件以及十字链表的结构定义

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ERROR 1;
#define OK 0;

typedef int Status;
typedef int ElemType;

typedef struct OLNode {
	int i, j;                      //该非0元所在行列
	ElemType e;                    //该非0元元素值
	struct OLNode* down, * right; //该非0元所在行列的后继链域
}OLNode, * OLink; //十字链表结构

typedef struct {
	OLink* rhead, * chead;   //行链表头指针,列链表头指针
	int mu, nu, tu;          //矩阵的行列与非0元个数
}CrossList;

初始化十字链表部分

创建矩阵前压迫初始化十字链表

void InitSmrix_OL(CrossList* M)//初始化十字链表
{
	M->rhead = M->chead = NULL;
	M->mu = M->nu = M->tu = 0;
}

创建十字链表函数

Status CreatSMarix_OL(CrossList* M)
{
	int i, j, k, m, n, t;
	OLNode* p, * q;
	ElemType e;
	printf("请输入矩阵的行列数和非0元个数:");
	scanf("%d %d %d", &m, &n, &t);
	M->mu = m;
	M->nu = n;
	M->tu = t;

	M->rhead = (OLink*)malloc((m + 1) * sizeof(OLink));
	if (!M->rhead)
	{
		printf("分配内存失败\n");
		return ERROR;
	}

	M->chead = (OLink*)malloc((n + 1) * sizeof(OLink));
	if (!M->chead)
	{
		printf("分配内存失败\n");
		return ERROR;
	}

	//初始化行列头指针
	for (k = 0; k <= m + 1; k++)
		M->rhead[k] = NULL;

	for (k = 0; k <= n + 1; k++)
		M->chead[k] = NULL;

	for (k = 0; k < t; k++)
	{
		printf("请输入非0元素所在行列与值(可任意输入)\n");
		scanf("%d %d %d", &i, &j, &e);
		p = (OLink)malloc(sizeof(OLNode));
		p->i = i; p->j = j; p->e = e;
		//开始排序
		if (M->rhead[i] == NULL || M->rhead[i]->j > p->j)
		{
			//如果这一行没有结点或者这一行的第一个结点列数大于新插入结点将这一结点插入在该行的第一个结点处
			p->right = M->rhead[i];
			M->rhead[i] = p;
		}
		else
		{
			for (q = M->rhead[i]; q->right && q->right->j < p->j; q = q->right); //寻找到p要插入的位置
			p->right = q->right;
			q->right = p;
		}
		//完成行插入
		if (M->chead[j] == NULL || M->chead[j]->i > p->i)
		{
			//如果这一列没有结点或者这一列的第一个结点的行大于新插入结点将这一结点插入在该列的第一个结点处
			p->down = M->chead[j];
			M->chead[j] = p;
		}
		else
		{
			for (q = M->chead[j]; q->down && q->down->i < p->i; q = q->down);
			//找到p列插入位置
			p->down = q->down;
			q->down = p;
		}
		//列插入完成
	}

	return OK;
}

打印稀疏矩阵函数

Status PrintSMartix(CrossList M)
{
	int i, j;
	OLNode* q;
	printf("开始遍历稀疏矩阵\n");
	
	if (!M.chead && !M.rhead)
	{
		printf("稀疏矩阵为空\n");
		return ERROR;
	}


	for (i = 1; i <= M.mu; i++)
	{
		q = M.rhead[i];
		for (j = 1; j <= M.nu; j++)
		{
			//如果此结点不为空且此结点的列数是按顺序的,打印此非0元
			if (q && q->j == j)
			{
				printf("%3d", q->e);
				q = q->right;
			}
			else
				printf("  0");
		}
		printf("\n");
	}
}

十字链表销毁函数

void DestroySMatrix(CrossList* M)
{
	int i;
	OLNode* p, * q;
	for (i = 1; i <= M->mu; i++)
	{
		p = M->rhead[i];
		while (p)
		{
			q = p;
			p = p->right;
			free(q);
		}
	}
	M->mu = M->nu = M->tu = 0;
	M->chead = M->rhead = NULL;
}

拷贝稀疏矩阵函数

拷贝的链表的链接形式虽然跟原链表一直,但他们的地址是不同的,拷贝的链表中的指针都不应该指向原链表中的结点,所以十字链表的拷贝与创建基本相同

Status CopySMartix(CrossList M, CrossList* T)
{
	int i;
	OLNode* p, * q, * r, * l;
	r = NULL;

	T->mu = M.mu;
	T->nu = M.nu;
	T->tu = M.tu;

	T->rhead = (OLink*)malloc((M.mu + 1) * sizeof(OLink));
	T->chead = (OLink*)malloc((M.nu + 1) * sizeof(OLink));
	if (!T->chead || !T->rhead)
	{
		printf("分配内存失败\n");
		return ERROR;
	}

	for (i = 0; i <= T->mu; i++)
		T->rhead[i] = NULL;
	for (i = 0; i <= T->nu; i++)
		T->chead[i] = NULL;

	for (i = 1; i <= M.mu; i++)
	{
		q = M.rhead[i];
		if (!q)
			continue;
		while (q)
		{
			p = (OLink)malloc(sizeof(OLNode));
			if (!p)
				return ERROR;
			p->i = q->i;
			p->j = q->j;
			p->e = q->e;

			p->right = p->down = NULL;

			if (T->rhead[q->i] == NULL)
				T->rhead[q->i] = p;
			else
				r->right = p;
			r = p;

			if (T->chead[q->j] == NULL || T->chead[q->j]->i > q->i)
			{
				r->down = T->chead[q->j];
				T->chead[q->j] = r;
			}
			else
			{
				for (l = T->chead[q->j]; l->down && l->down->i < p->i; l = l->down);
				r->down = l->down;
				l->down = r;
			}
			q = q->right;
		}
	}

	return OK;
}

完整头文件

#define _CRT_SECURE_NO_WARNINGS 1

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define ERROR 1;
#define OK 0;

typedef int Status;
typedef int ElemType;

typedef struct OLNode {
	int i, j;                      //该非0元所在行列
	ElemType e;                    //该非0元元素值
	struct OLNode* down, * right; //该非0元所在行列的后继链域
}OLNode, * OLink; //十字链表结构

typedef struct {
	OLink* rhead, * chead;   //行链表头指针,列链表头指针
	int mu, nu, tu;          //矩阵的行列与非0元个数
}CrossList;


void InitSmrix_OL(CrossList* M)//初始化十字链表
{
	M->rhead = M->chead = NULL;
	M->mu = M->nu = M->tu = 0;
}

//十字链表创建稀疏矩阵
Status CreatSMarix_OL(CrossList* M)
{
	int i, j, k, m, n, t;
	OLNode* p, * q;
	ElemType e;
	printf("请输入矩阵的行列数和非0元个数:");
	scanf("%d %d %d", &m, &n, &t);
	M->mu = m;
	M->nu = n;
	M->tu = t;

	M->rhead = (OLink*)malloc((m + 1) * sizeof(OLink));
	if (!M->rhead)
	{
		printf("分配内存失败\n");
		return ERROR;
	}

	M->chead = (OLink*)malloc((n + 1) * sizeof(OLink));
	if (!M->chead)
	{
		printf("分配内存失败\n");
		return ERROR;
	}

	//初始化行列头指针
	for (k = 0; k <= m; k++)
		M->rhead[k] = NULL;

	for (k = 0; k <= m; k++)
		M->chead[k] = NULL;

	for (k = 0; k < t; k++)
	{
		printf("请输入非0元素所在行列与值(可任意输入)\n");
		scanf("%d %d %d", &i, &j, &e);
		p = (OLink)malloc(sizeof(OLNode));
		p->i = i; p->j = j; p->e = e;
		//开始排序
		if (M->rhead[i] == NULL || M->rhead[i]->j > p->j)
		{
			//如果这一行没有结点或者这一行的第一个结点列数大于新插入结点将这一结点插入在该行的第一个结点处
			p->right = M->rhead[i];
			M->rhead[i] = p;
		}
		else
		{
			for (q = M->rhead[i]; q->right && q->right->j < p->j; q = q->right); //寻找到p要插入的位置
			p->right = q->right;
			q->right = p;
		}
		//完成行插入
		if (M->chead[j] == NULL || M->chead[j]->i > p->i)
		{
			//如果这一列没有结点或者这一列的第一个结点的行大于新插入结点将这一结点插入在该列的第一个结点处
			p->down = M->chead[j];
			M->chead[j] = p;
		}
		else
		{
			for (q = M->chead[j]; q->down && q->down->i < p->i; q = q->down);
			//找到p列插入位置
			p->down = q->down;
			q->down = p;
		}
		//列插入完成
	}

	return OK;
}

//打印矩阵函数
Status PrintSMartix(CrossList M)
{
	int i, j;
	OLNode* q;
	printf("开始遍历稀疏矩阵\n");
	
	if (!M.chead && !M.rhead)
	{
		printf("稀疏矩阵为空\n");
		return ERROR;
	}


	for (i = 1; i <= M.mu; i++)
	{
		q = M.rhead[i];
		for (j = 1; j <= M.nu; j++)
		{
			//如果此结点不为空且此结点的列数是按顺序的,打印此非0元
			if (q && q->j == j)
			{
				printf("%3d", q->e);
				q = q->right;
			}
			else
				printf("  0");
		}
		printf("\n");
	}
}

//十字链表销毁函数 
void DestroySMatrix(CrossList* M)
{
	int i;
	OLNode* p, * q;
	for (i = 1; i <= M->mu; i++)
	{
		p = M->rhead[i];
		while (p)
		{
			q = p;
			p = p->right;
			free(q);
		}
	}
	M->mu = M->nu = M->tu = 0;
	M->chead = M->rhead = NULL;
}

//稀疏矩阵的拷贝
Status CopySMartix(CrossList M, CrossList* T)
{
	int i;
	OLNode* p, * q, * r, * l;
	r = NULL;

	T->mu = M.mu;
	T->nu = M.nu;
	T->tu = M.tu;

	T->rhead = (OLink*)malloc((M.mu + 1) * sizeof(OLink));
	T->chead = (OLink*)malloc((M.nu + 1) * sizeof(OLink));
	if (!T->chead || !T->rhead)
	{
		printf("分配内存失败\n");
		return ERROR;
	}

	for (i = 0; i <= T->mu; i++)
		T->rhead[i] = NULL;
	for (i = 0; i <= T->nu; i++)
		T->chead[i] = NULL;

	for (i = 1; i <= M.mu; i++)
	{
		q = M.rhead[i];
		if (!q)
			continue;
		while (q)
		{
			p = (OLink)malloc(sizeof(OLNode));
			if (!p)
				return ERROR;
			p->i = q->i;
			p->j = q->j;
			p->e = q->e;

			p->right = p->down = NULL;

			if (T->rhead[q->i] == NULL)
				T->rhead[q->i] = p;
			else
				r->right = p;
			r = p;

			if (T->chead[q->j] == NULL || T->chead[q->j]->i > q->i)
			{
				r->down = T->chead[q->j];
				T->chead[q->j] = r;
			}
			else
			{
				for (l = T->chead[q->j]; l->down && l->down->i < p->i; l = l->down);
				r->down = l->down;
				l->down = r;
			}
			q = q->right;
		}
	}

	return OK;
}


源函数部分

测试头文件中的函数

#include "CrossList.h"

int main()
{
	CrossList L;

	printf("测试函数CreatSMarix_OL\n");
	{
		InitSmrix_OL(&L);
		CreatSMarix_OL(&L);
		PrintSMartix(L);
	}


	printf("测试函数CopySMartix\n");
	{
		CrossList Q;
		CopySMartix(L, &Q);
		printf("复制矩阵Q为\n");
		PrintSMartix(Q);
	}

	printf("测试函数DestroySMatrix\n");
	{
		DestroySMatrix(&L);
		PrintSMartix(L);
	}
	
	return 0;
}
  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值