如何使用C中的链表进行大整数乘法



我接受字符串格式的输入。然后我将每个数字转换为整数,并将每个数字存储在链表节点中。我本可以使用数组,但避免使用,因为它们有内存限制并且是静态的。请告诉我下面的代码哪里出错了?

# include<stdio.h>
# include<stdlib.h>
# include<string.h>
  struct ll{
    int digit;
    int place;
    struct ll *next;
  };

  typedef struct ll node;
    node *insert(node *head,int dig, int plac)//to insert new nodes{
         if(head==NULL){
            head=(node *)malloc(sizeof(node));
            head->digit=dig;
            head->place=plac;
            head->next=NULL;
            return head;
        }
        else{   
            head->next=insert(head->next,dig,plac);
            return head;
        }   
    }
    void print(node *a)//to print all the nodes in the linked list{
        node *temp;
        temp=a;
        while(temp!=NULL){
            printf("%dn",temp->digit);
            temp=temp->next;
        }
    }
    node *string_to_trainofdig(char h[],node *head){                     //converting a string to integer digits and storing them individually in the linked list
        int q,i;
        q=strlen(h);int j;node *temp;temp=(node *)malloc(sizeof(node));
        printf("value of q is %dn",q);
        for(i=q-1;i>=0;i--){
            printf("value of i %dn",i);
            switch(h[i]){       
                case '0':j=0;break;
                case '1':j=1;break;
                case '2':j=2;break;
                case '3':j=3;break;
                case '4':j=4;break;
                case '5':j=5;break;
                case '6':j=6;break;
                case '7':j=7;break;
                case '8':j=8;break;
                case '9':j=9;break; 
            }
            printf("j is %dn",j);
            temp=insert(head,j,i);
            head=temp;
        }
        return temp;
    }

    int count(node *q){                          //counting the total number of nodes in a linked list
        int p=0;;
        node *w;
        w=q;
        while(w!=NULL){
            p++;
            w=w->next;              
        }
        return p;   
    }

    int pos(node *a, int y){                  //this function returns the digit stored in a   //particular node (specified by its position) 
        y--;
        node *temp; temp=a;
        if(a==NULL){
            return 0;
        }
        else{   
            while(temp!=NULL || y!=0){
                temp=temp->next;
                    y--;
            }
            if(temp==NULL){
                return 0;
            }
            else if(y==0){
                return temp->digit;             
            }
        }       
    }
    node *modify(node *a,int value,int posi){   /*inserts nodes and assigns them     //values if empty (NULL) but modifies the value stored in that position in the //linked list if not NULL*/
        node *temp; temp=a; posi--;
        if(a==NULL){
            return insert(a,value,posi);
        }
        else{   
            while(temp!=NULL || posi!=0){
                temp=temp->next;
                posi--;
            }
            if(temp==NULL){
                return NULL;
            }
            else if(posi==0){
              temp->digit=value;
            }
            return a;
        }
    }
    char *mult(node *a,node *b){               //taking two linked lists as parameters and  multiplying them 
        char e[1000000];
        node *as; node *bs;
        as=a;bs=b; 
        int z,x,m,n,v,r;
        m=0; n=0;
        node *newe;node *newe2;
        char er[1000000];
        newe=NULL;
        int s;
        s=count(a)>count(b)?count(a):count(b);
        as=count(a)>count(b)?a:b;//determines which linked list is bigger and     //assigns that to as
        bs=count(a)>count(b)?b:a;//bs is smaller of the two linkedc lists
        int fr=0;int ca=0;  int i=0;
        while(bs!=NULL)//main algorithm{
            i=fr;//fr is initially 0
            while(as!=NULL){
                m=as->digit*bs->digit+m;//m is zero initially
                n=m%10;
                m=m/10;
                ca=(pos(newe,i));// ca gets the value stored in the ith position of node  //newe---->will be 0 initially since NULL 
                newe=modify(newe,n+ca,i);
                as=as->next;i++;        
            }
            as=count(a)>count(b)?a:b;
            bs=bs->next;    
            fr++;//increments fr so that i comes back to fr
        }
    }

    main(){
        char d[1000]; char p[1000];
        scanf("%s",d);
        scanf("%s",p);
        int q,w;
        node *l,*u; l=NULL; u=NULL;
        l=string_to_trainofdig(d,l);
        u=string_to_trainofdig(p,u);
        print(l);
        print(u);   
        char *t;
        t=mult(l,u);
        printf("donen");
    }

链表(尤其是在这种情况下)的性能非常差。每次跟随链接(例如temp=temp->next;),都可能是缓存未命中,并破坏现代(无序)CPU上的指令并行性,因为后续代码所依赖的temp的新值要到之后才能知道。它们还倾向于将数据分散到各处(缓存局部性差),这使前两个问题变得更糟,并使线性迭代"不可预取"(不像"对于阵列中的每个元素",CPU可以简单地检测模式并在需要之前预取数据)。

对于大整数,将整数存储为"基数10"也会导致性能极差。这只是由效率较低的内存使用引起的(例如,在本可以存储0到255的值的每个字节中存储0到9的值)。主要问题是,大多数高级运算都有"每位数"开销(加法、减法、AND、OR)或"每位数平方"开销(乘法)。小基数(例如"基数10")意味着更多的数字,这意味着大量的开销。较大的基数(例如"基数4294967296")意味着更少的数字和更少的开销。除此之外,使用"2的幂"大小可以使用移位和掩蔽,而不是模数和除法(例如digit = temp%10; temp /= 10;digit = temp & 0xFF; temp >>= 8;);并且使用"整整数"大小使其更加高效(digit = temp; temp >>= 32;)。大体上要获得可接受的性能,您需要匹配CPU的本机大小-例如,在32位系统上使用"base4294967296",在64位系统上则使用"base18446744073709551616"。

如果你把这两者结合起来,你可能会得到更像的东西

    typedef struct {
        int current_digits;
        int allocated_digits;
        uint32_t digits[];
    } BIG_INTEGER;

请注意,current_digitsallocated_digits字段可以避免一直调整数组的大小。例如:

#define EXTRA_DIGITS    16
    if(number->current_digits + 1 < number->allocated_digits) {
        number->allocated_digits = number->current_digits + 1 + EXTRA_DIGITS;
        newsize = sizeof(BIG_INTEGER) + sizeof(uint32_t)*number->allocated_digits;
        number = realloc(number, newsize);
    }
    number->digits[number->current_digits] = 0;
    number->current_digits++;

对于乘法本身;它大致是这样的(假设32位或uint32_t用于数字,根本没有测试):

    uint64_t temp;             // Must be double the size of a digit
    for(i = 0; i < number1->current_digits; i++) {
        for(j = 0; j < number2->current_digits; j++) {
            temp = number1->digits[i] * number2->digits[j];
            k = i+j;
            while(temp != 0) {
                temp = temp + result->digits[k];
                result->digits[k] = temp;    // Lower half only
                temp = temp >> 32;
                k++;
            }
        }
    }

您可能可以将其转换为使用链表而不是数组;但是

如果你试图用任意长的整数进行整数数学运算,我建议你使用GMP库或类似的库,而不是自己做。

我本可以使用数组,但避免了,因为它们有内存限制,而且是静态

这是不对的。虽然您可以在C中将数组声明为静态块,但您可以根据需要简单地声明一个指针和malloc()空间(当然要记住free())。

请告诉我下面的代码哪里出错了?

当发布问题时,这种含糊的提问方式是不可取的。

您告诉我们正在发生的事情和您的期望,一些示例输入和输出或错误报告。

相关内容

  • 没有找到相关文章

最新更新