1. 程式人生 > >稀疏矩陣利用三元組相乘(c語言)

稀疏矩陣利用三元組相乘(c語言)

被這個稀疏矩陣折磨了很久,看了將近一個半禮拜,看的我很想撕書。
這個是程式思想是和資料結構(c語言版)機械工業出版社的學習的,書 程式碼講解不是很詳細,搜了網上很多程式碼,都是抄了一下,草草註釋,在我自己寫的時候發現書上的程式碼是有問題的。
書上p48,new_b使用int型別,但是轉置是term型別,而且轉置都是用了一位陣列。
還有就是書上的邊界條件處理的是有問題的,如果原封不動的寫,最後結果會是兩行疊加的答案,我寫了兩種方法
書上顯然是錯的,查了很多中文版本,程式碼都是錯的,沒有查到英文版,不知道是什麼狀況,有哪位看到英文版的程式碼,請給我發一下原版,不勝感激!!!
都說國外書很好,但是我覺得還是自己多動手,不能光看,盡信書不如無書,這個題也警示我要多動手!!!

大家只要耐心的看程式下面的圖就可以大概瞭解過程,過程圖是我自己畫的,畫的不是太好,如果大家覺得這篇部落格可以幫到你,大家可以隨意轉載,能幫到大家非常開心,寫的不對的地方希望大家提出來,希望和大家一起進步!!!

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#define MAX_TERMS 101
#define MAX_COL 50
typedef struct{
    int col;
    int row;
    int value;
}term;
term a[MAX_TERMS];
term b[MAX_TERMS];
term d[MAX_TERMS];
void
fast_transpose(term a[],term b[]); void mmult(term a[],term b[],term d[]); int compare(int a,int b); void storesum(term d[],int *totald,int row,int column,int *sum); int main() { int value; int count = 1; printf("請輸入將要輸入a矩陣的行和列數\n"); scanf("%d%d",&a[0].row,&a[0].col); printf
("請輸入資料\n"); for(int i = 1;i <= a[0].row;i++) for(int j = 1;j <= a[0].col;j++) { scanf(" %d",&value); if(value != 0) { a[count].row = i; a[count].col = j; a[count].value = value; count++; } } a[0].value = count-1; count = 1; printf("請輸入將要輸入b矩陣的行和列數\n"); scanf("%d%d",&b[0].row,&b[0].col); printf("請輸入資料\n"); for(int i = 1;i <= b[0].row;i++) for(int j = 1;j <= b[0].col;j++) { scanf(" %d",&value); if(value != 0) { b[count].row = i; b[count].col = j; b[count].value = value; count++; } } b[0].value = count-1; mmult(a,b,d); for(int i=1; i <= d[0].value;i++)//最後輸出結果 printf("%d %d value is %d\n",d[i].row,d[i].col,d[i].value); } void fast_transpose(term a[],term b[])//轉置 { int row_term[MAX_COL],starting_pos[MAX_COL]; int i,j,num_cols=a[0].col,num_terms = a[0].value; b[0].row = num_cols;b[0].col = a[0].row; b[0].value = num_terms; if(num_terms > 0)//非零矩陣 { memset(row_term,0,sizeof(row_term)); for(int i =1;i <= num_terms;i++)//個數取決於a中非零元素個數 row_term[a[i].col]++; starting_pos[0]=1; for(int i = 1;i <= num_cols;i++) starting_pos[i] = starting_pos[i-1] + row_term[i-1]; for(int i = 1;i <= num_terms;i++) { j=starting_pos[a[i].col]++; b[j].row = a[i].col;b[j].col = a[i].row; b[j].value = a[i].value; } } } void mmult(term a[],term b[],term d[]) { int i,j,column,totalb = b[0].value,totald = 0; int rows_a = a[0].row,cols_a = a[0].col; int totala = a[0].value,cols_b = b[0].col; int row_begin = 1,row = a[1].row,sum = 0; term new_b[MAX_TERMS]; if(cols_a !=b[0].row) { fprintf(stderr,"Incompatible matrices\n"); exit(1); } fast_transpose(b,new_b); //因為b三元組轉置之後,a和b就可以直接行和行相乘,方便操作 a[totala+1].row = rows_a; new_b[totalb+1].row = cols_b + 1; //哨兵存在的意義就是有可能一個三元組計算完,另一個三元組不能計算 // ↑方法一: 改變哨兵條件,當進入哨兵位置時,哨兵給予一個不存在的行(大於所有行) // 此時當j=totalb+1時會進入else if(new_b[j].row!=column)這一句,自動儲存本列的乘積 new_b[totalb+1].col = 0; //轉置的三元組有一個超過本來長度的元素好處是 //進入下面的compare函式,j++,代表又有一列結束,需要sum++ //不然就會出現上一行結果和下一行結果相加的情況 for(i = 1;i <= totala;) { column = new_b[1].row; for(j = 1;j <= totalb + 1;) { if(a[i].row!=row)//a三元組和開始的行號不等,證明左邊矩陣需要換行,進行sum { storesum(d,&totald,row,column,&sum); i = row_begin; for(;new_b[j].row == column;j++) ; column = new_b[j].row;//a要更新一行和b的起始相乘; } else if(new_b[j].row!=column) { storesum(d,&totald,row,column,&sum); i = row_begin; column = new_b[j].row; } else switch(compare(a[i].col,new_b[j].col)) { case -1 : i++; break; case 0: sum +=(a[i].value*new_b[j].value); i++; j++; break; case 1: j++; break; } // 方法二:當執行到哨兵位置時,說明即將換列,此時將本列的乘積儲存起來 // if (j == totalb + 1) // { // storesum(d,&totald,row,column,&sum); // } } //a需要換行,所有一旦不滿足現在的行號,證明換行成功 for(;a[i].row == row;i++) ; row_begin = i;//a的新的開始 row = a[i].row;//新行號 } d[0].row = rows_a;//將最後的非零元素統計 d[0].col = cols_b; d[0].value = totald; } int compare(int a,int b) { if(a > b) return 1; if(a == b) return 0; if (a < b) return -1; } void storesum(term d[],int *totald,int row,int column,int *sum) { if(*sum)//只有乘積不為零才記錄 { if(*totald < MAX_TERMS)//防止總共的d元素超過定義的最大數 { d[++*totald].row = row; d[*totald].col = column; d[*totald].value = *sum; *sum = 0; } else { fprintf(stderr,"Numbers of terms in product exceeds %d\n",MAX_TERMS); exit(1); } } }

這裡寫圖片描述
這裡寫圖片描述