您的位置:首页 > 理论基础 > 数据结构算法

网易云课堂-陈越、何钦铭-数据结构-2016春,02-线性结构1 一元多项式的乘法与加法运算,学习笔记

2016-03-07 10:38 2006 查看
设计函数分别求两个一元多项式的乘积与和。


输入格式:

输入分2行,每行分别先给出多项式非零项的个数,再以指数递降方式输入一个多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。

输出格式:

输出分2行,分别以指数递降方式输出乘积多项式以及和多项式非零项的系数和指数。数字间以空格分隔,但结尾不能有多余空格。零多项式应输出
0 0


输入样例:

4 3 4 -5 2  6 1  -2 0
3 5 20  -7 4  3 1
[/code]

输出样例:

15 24 -25 22 30 21 -10 20 -21 8 35 6 -33 5 14 4 -15 3 18 2 -6 1
5 20 -4 4 -5 2 9 1 -2 0
[/code]

基本思路是用一个链表,然后手算怎么算编程就怎么算。





得先写出来一个链表

这是根据书上的例程写的,其中关于struct和typedef struct的知识点如下:

1)C语言中的结构体
http://blog.csdn.net/huqinwei987/article/details/23625823
----------------------------------------------------------------------------------------------------------------------------------------

基本定义:结构体,通俗讲就像是打包封装,把一些有共同特征(比如同属于某一类事物的属性,往往是某种业务相关属性的聚合)的变量封装在内部,通过一定方法访问修改内部变量。
(类似于C++的“类”)
结构体定义:
 
第一种:只有结构体定义
struct stuff{  
        char job[20];  
        int age;  
        float height;  
};  
 
第二种:附加该结构体类型的“结构体变量”的初始化的结构体定义
//直接带变量名Huqinwei  
struct stuff{  
        char job[20];  
        int age;  
        float height;  
}Huqinwei;  
也许初期看不习惯容易困惑,其实这就相当于:
 
struct stuff{  
        char job[20];  
        int age;  
        float height;  
};  
struct stuff Huqinwei;  
 
第三种:如果该结构体你只用一个变量Huqinwei,而不再需要用
struct stuff yourname;  
去定义第二个变量。
那么,附加变量初始化的结构体定义还可进一步简化出第三种
struct{  
        char job[20];  
        int age;  
        float height;  
}Huqinwei;  
把结构体名称去掉,这样更简洁,不过也不能定义其他同结构体变量了——至少我现在没掌握这种方法。
----------------------------------------------------------------------------------------------------------------------------------------
结构体变量及其内部成员变量的定义及访问:
绕口吧?要分清结构体变量和结构体内部成员变量的概念。
就像刚才的第二种提到的,结构体变量的声明可以用:
struct stuff yourname;  
其成员变量的定义可以随声明进行:

【初始化】

struct stuff Huqinwei = {"manager",30,185};  
也可以考虑结构体之间的赋值:
       struct stuff faker = Huqinwei;  
//或    struct stuff faker2;  
//      faker2 = faker;  
打印,可见结构体的每一个成员变量一模一样  
如果不使用上边两种方法,那么成员数组的操作会稍微麻烦(用for循环可能好点)
Huqinwei.job[0] = 'M';  
Huqinwei.job[1] = 'a';  
Huqinwei.age = 27;  
nbsp;Huqinwei.height = 185;  
结构体成员变量的访问除了可以借助符号".",还可以用"->"访问(下边会提)。
----------------------------------------------------------------------------------------------------------------------------------------
 
 
指针和数组:
这是永远绕不开的话题,首先是引用:

【这个貌似不是引用吧。。。这个是定义了struct stuff *指针之后取了个地址。。。类似“    int a = 0;    int *p = &a;”】

    struct stuff *ref = &Huqinwei;  
    ref->age = 100;  
   printf("age is:%d\n",Huqinwei.age);  
指针也是一样的
<span style="font-size:18
101bf
px;">#include<stdio.h>

main()

{

struct abc{

int a;};

<span style="background-color: rgb(255, 0, 0);">struct abc *p</span>;

p->a=1;

printf("%d",p->a);

}</span>


这个编译没有问题,但是运行是段错误,请问为什么呢,谢谢了
因为你定义了一个结构体指针p,用来指向此类(struct abc)结构体,但是你却没有给他赋值,此时p的值为NULL,你并没有在内存中为p分配任何空间,所以p->a=1这句就会出段错误。
修改方法1:可以给p分配一段内存空间,并使其指向此空间:
p=(struct abc *)malloc(sizeof(struct abc));
p->a = 1;
方法2:可以让p指向一个已存在的内存空间:
struct abc temp;
p=&temp;
p->a = 1;
结构体也不能免俗,必须有数组:
struct test{  
        int a[3];  
        int b;  
};  
//对于数组和变量同时存在的情况,有如下定义方法:  
        struct test student[3] =      {//这个大括号是结构体数组的“轮廓”
                                        {{66,77,55},0},  //这是一个结构体变量,最里面的大括号是 int a[3]的。
                                        {{44,65,33},0},  
                                        {{46,99,77},0}
                                                  };  
//特别的,可以简化成:  
        struct test student[3] =       {{66,77,55,0},  
                                        {44,65,33,0},  
                                        {46,99,77,0}};  //最外面的大括号可以去掉

----------------------------------------------------------------------------------------------------------------------------------------

 
占用内存空间:
struct结构体,在结构体定义的时候不能申请内存空间,不过如果是结构体变量,声明的时候就可以分配——两者关系就像C++的类与对象,对象才分配内存(不过严格讲,作为代码段,结构体定义部分“.text”真的就不占空间了么?当然,这是另外一个范畴的话题)。
 
结构体的大小是结构体所含变量大小的总和,并且不能用"char a[]"这种弹性(flexible)变量,必须明确大小,下面打印输出上述结构体的size:
      printf("size of struct man:%d\n",sizeof(struct man));  
        printf("size:%d\n",sizeof(Huqinwei));  
结果毫无悬念,都是28:分别是char数组20,int变量4,浮点变量4.   
 
和C++的类不一样,结构体不可以给结构体内部变量初始化,。
如下,为错误示范:
#include<stdio.h>  
//直接带变量名Huqinwei  
struct stuff{  
//      char job[20] = "Programmer";  
//      char job[];  
//      int age = 27;  
//      float height = 185;  
}Huqinwei;  
 
 
PS:结构体的声明也要注意位置的,作用域不一样。
C++的结构体变量的声明定义和C有略微不同,说白了就是更“面向对象”风格化,要求更低。

----------------------------------------------------------------------------------------------------------------------------------------

所以我的代码写起来就是:

<span style="font-size:18px;">struct Node;//对结构体Node的声明
/*之所以这样写是因为Node结构体里要包含一个指向下一个【它本身】的指针,
所以要先用struct Node;声明,然后再用typedef定义指针,最后才可以在struct中使用这个指针*/
typedef struct Node * PointerToNode;//注意这个语法
typedef PointerToNode Position;//链表内部的指针
typedef PointerToNode List;//链表头部,即指向链表的指针
struct Node
{
int index;
int coefficient;
Position Next;
};</span>
----------------------------------------------------------------------------------------------------------------------------------------
这个是链表的单个节点的定义,下面要写一下可能会用到的函数【就是数据结构里的那些插入删除之类的操作】:

【这个貌似与需要什么样的操作有关系,比如我解决这个具体的问题不一定要用到插入之类的。】

----------------------------------------------------------------------------------------------------------------------------------------

按照老师的讲解,对问题(和数据结构)的分析可以从“关键数据”上入手:

在“多项式”这个问题上,“关键数据”其实有3个——非零项的个数、系数和指数。【其实就是输入。。。】

如果从“线性无关”的角度思考其实后两者决定了非零项的个数。

所以问题的关键就是“如何保存系数和指数”。

一个最直观的想法是用一维数组;指数 =下标,系数=数组元素。



不过这显然不靠谱——(1)内存浪费在0项上了;(2)没法推广到3个元素的数据结构上。

然后就是用结构体(C++里面的“类”)

大致上是下面这个思路:

<span style="font-size:18px;">struct term
{
int index;
int coefficient;
};

struct term [2] = { {1,2},{3,4} };</span>




然后,每一项用指针i,j之类的指向;比如第一项就是term[0],遍历就用term[i]……

用链表的话,就只是比struct数组多一个指向下一Node的指针,代码大概是这个样子滴:

<span style="font-size:18px;">struct Node;//对结构体Node的声明
/*之所以这样写是因为Node结构体里要包含一个指向下一个【它本身】的指针,
所以要先用struct Node;声明,然后再用typedef定义指针,最后才可以在struct中使用这个指针*/
typedef struct Node * PointerToNode;//注意这个语法
typedef PointerToNode Position;//链表内部的指针
typedef PointerToNode List;//链表头部,即指向链表的指针
struct Node
{
int index;
int coefficient;
Position Next;
};</span>






----------------------------------------------------------------------------------------------------------------------------------------

老师用struct数组做的多项式加法跟我自己瞎想的思路是一样的,都是“比较指数->大的进入,小的留在外面,相等的话系数相加”这个思路。

拿链表的数据结构来试着写一个计算多项式加法的函数。

关于链表的编程:

1、不要用初始化数组或结构的方式去处理链表;

2、链表的每一个节点要用一个子程序进行动态创建,同时赋值;

3、删除链表中的节点时,要注意回收内存;

首先就卡在了“如何初始化一个链表”上:

////////////////////////////////////////////

对“头结点”体会不深

对“头结点”的思考和验证:




其中,Answer_Poly就是“头指针”,它指向的是链表的第一个结点,链表的第一个结点的三个元素可以这么访问:

<span style="font-size:18px;">	//(4-3)对第一个结点的操作可以如下进行
AnswerPoly->coefficient = 0;
AnswerPoly->index = 0;
AnswerPoly->Next = NULL;</span>


////////////////////////////////////////////

----------------------------------------------------------------------------------------------------------------------------------------

“线性表(Linear List)”:由同类型数据元素构成有序序列的线性结构

 表中元素个数称为线性表的长度

 线性表没有元素时,称为空表

 表起始位置称表头,表结束位置称表尾

类型名称:线性表(List)  

数据对象集:线性表是 n (≥0)个元素构成的有序序列( a1, a2, ……,an )

操作集:线性表L 属于 List,整数i表示位置,元素X属于 ElementType,

                线性表基本操作主要有:  

1、List MakeEmpty():初始化一个空线性表L;

2、ElementType FindKth( int K, List L ):根据位序K,返回相应元素 ;

3、int Find( ElementType X, List L ):在线性表L中查找X的第一次出现位置;

4、void Insert( ElementType X, int i, List L):在位序i前插入一个新元素X;

5、void Delete( int  i, List L ):删除指定位序i的元素;

6、int Length( List L ):返回线性表L的长度n。

----------------------------------------------------------------------------------------------------------------------------------------



<span style="font-size:18px;">//#define之类的后面没有分号
#define Maxsize 100
//#typedef Elementtype int
//typedef不用加#
//typedef Elementtype int;写反了,应该是:
typedef int Elementtype;</span>

<span style="font-size:18px;">//顺序存储的线性表——定义的结构体是整个线性表,并不是一个node
struct SequentialStorageList
{
Elementtype Data[Maxsize];
int Last;
};
typedef struct SequentialStorageList * PtrToSequentialStorageList;
</span>



<span style="font-size:18px;">//【1】建立一个空的线性表
//(1)确定输入——为空,和输出——返回一个指向链表的指针;
PtrToSequentialStorageList MakeEmptyForSequentialStorageList()
{
PtrToSequentialStorageList List;
List = (PtrToSequentialStorageList)malloc(sizeof(struct SequentialStorageList));
//List->Data = {};这个不必要管,因为全置零也就不是“空表”了,而是“全为0的表”了
//Last是“指向最后一个元素【标号】的指针”,如果为0的话代表位置为0的地方有一个元素,那不是空表。
List->Last = -1;
return List;
}</span>


下面这个是我瞎想的for循环写法
<span style="font-size:18px;">int FindForSequentialStorageList(Elementtype X, PtrToSequentialStorageList List)
{
//注意:命名不能跟#define重复
//循环是0开始,Max_size-1【即<Max_size】结束,因此Last+1
int Max_size = List->Last+1;
for (int i = 0; i < Max_size; i++)
{
if (List->Data[i] == X)
return i;
}
return -1;
}</span>


这个是老师的while写法:
<span style="font-size:18px;">int FindWhileSequentialStorageList(Elementtype X, PtrToSequentialStorageList List)
{
int Max_size = List->Last + 1;
int i = 0;
while (i<Max_size&&List->Data[i]!=X)
{
i++;
}
//跳出循环只有两种可能
 if (i >= Max_size)
return -1;
else
return i;

}</span>





<span style="font-size:18px;">void InsertOfSequentialStorageList(Elementtype X, PtrToSequentialStorageList List,int index)
{
//insert的三种可能情况
//(1)Data[]数组已满,插不进去了
//(2)插入的位置不合法
//(3)可以正确插入
if (List->Last == Maxsize - 1)
{
printf("%s\n", "Out of memory");
return;
}
//我们最多可以在0处和Last+1处插入,而不能隔一个空白插入
if (index<0 || index>List->Last + 1)
{
printf("%s\n", "Illegal index");
return;
}
else
{
//从index指向的那个元素到最后一个元素,全部向后移动一位
//for (int j = index; j <= List->Last; j++)错!应该从后往前移动
for (int j = List->Last; j >= index;j--)
{
List->Data[j + 1] = List->Data[j];//向后移动一位
}
List->Data[index] = X;
//这个我忘了:
List->Last++;
}

}</span>






<span style="font-size:18px;">//删除下标为i的那个元素
void DeleteOfSequentialStorageList(int index, PtrToSequentialStorageList List)
{
//自己写函数也一定要注意“异常处理”
//以下的代码是看了老师的程序之后才想起来的
if (index<0 || index>List->Last)
{
printf("不存在第%d个元素",index);
//返回值为void的函数,千万不要要忘了写return;
return;
}
//从index后面一个开始移动
for (int i = index+1; i <= List->Last; i++)
{
List->Data[i - 1] = List->Data[i];

}
//这个一定要注意
//一共有两个结构体的“域”,所以两个的更新都要考虑。
List->Last = List->Last - 1;
//!!!千万不要忘了写return!!!
return;
}</span>

----------------------------------------------------------------------------------------------------------------------------------------

顺序存储方式保存的线性表的四大操作就告一段落了,下面开始是链表的部分。

----------------------------------------------------------------------------------------------------------------------------------------

(1)链表就是把数组的“相邻”变成了“指针”。

(2)【从定义的结构体看】带来了访问第i个元素,以及确定链表长度的困难。

typedef struct Node * PointerToNode;//注意这个语法
typedef PointerToNode Position;//链表内部的指针
typedef PointerToNode List;//链表头部,即指向链表的指针
struct Node
{
int index;
int coefficient;
Position Next;
};

数组List->Data[i]和List->Last即可

(2-1)确定链表的长度。



 

//下面是链表的getLength函数
int GetLengthOfLinkedList(LinkedList List)
{
PointerToNode P = List;
int i=0;
while (P)
{
P = P->Next;
i++;
}
return i;

}
//下面是链表的查找第K个元素
//返回值应该是啥?是指向那个元素的指针还是Elementtype?
//老师给的是指针
//想想指针也有道理
//返回指向给出的下标为K的元素的指针
PointerToNode FindKthOfLinkedList(LinkedList List, int K)
{
PointerToNode Pointer = List;
//避免非法输入
int Length = 0;
Length = GetLengthOfLinkedList(List);
//这个是0,1,2,……,length-1,所以一共有length个元素
if (K<0 || K>Length - 1)
{
printf("下标超出");
//return啥?
//是指针啊,也只能return NULL了。
return NULL;
}
//正式开始
//确定终止条件
//(1)找到
int i = 0;
//(2)超出
//while (||Pointer!=NULL)
while (Pointer)
{
i++;
if (i == K)
{
return Pointer;
}
Pointer = Pointer->Next;
}
return NULL;

}


 



 

PointerToNode FindKthOfLinkedList_TeacherVersion(LinkedList List, int K)
{
//给表头
PointerToNode p = List;
//存下标
int i = 0;
//两个条件
while (p != NULL || i < K)
{
i++;
p = p->Next;
}
//判断是哪种原因
if (i == K)
return p;
else
return NULL;
}


 

//下面的这个是查找第一个元素为X的函数
PointerToNode FindFirstNodeWithElementXOfLinkedList(Elementtype X, LinkedList List)
{
PointerToNode p = List;
while (p!=NULL||p->Data!=X)
{
p = p->Next;
}
//以下全部内容都可以优化为一句:return p;
//因为跳出的条件要么是p==NULL,要么是->Data==X
if (p->Data == X)
{
return p;
}
else
return NULL;

}


 

//插入(我用的返回值是void)
//在index处插入,即,在index-1结点后面插入
void InsertOfLinkedListReturnVoid(Elementtype X, LinkedList List,int index)
{
//要先新构造一个节点
PointerToNode NewNode = NULL;
NewNode = (PointerToNode)malloc(sizeof(struct Node));
//看看是否构建成功了
if (NewNode == NULL)
{
printf("Out of space");
return;
}
//把结点加上去
//!!!!!!!!!!!!!!!!!!思考不全面!!!!!!!!!!!!!
//如果index是0,怎么办?
//需要改动头指针
if (index == 0)
{
NewNode->Next = List;
NewNode->Data = X;
List = NewNode;
//!!!!!!注意别忘记放Data!!!!!!!!!

return;
}
//	找到index-1结点
PointerToNode PointerToIndex_1 = NULL;
PointerToIndex_1 = FindKthOfLinkedList_TeacherVersion(List,index-1);
//先挂上后面的
NewNode->Next = PointerToIndex_1->Next;
//再把NewNode挂上去
PointerToIndex_1->Next = NewNode;
return;
}
//老师用的是List--返回插入之后的链表(这个似乎更好一点?)
LinkedList InsertOfLinkedListReturnVoidReturnLinkedList(Elementtype X, LinkedList List, int index)
{
//要先新构造一个节点
PointerToNode NewNode = NULL;
NewNode = (PointerToNode)malloc(sizeof(struct Node));
//看看是否构建成功了
if (NewNode == NULL)
{
printf("Out of space");
return List;
}
//把结点加上去
//!!!!!!!!!!!!!!!!!!思考不全面!!!!!!!!!!!!!
//如果index是0,怎么办?
//需要改动头指针
if (index == 0)
{
NewNode->Next = List;
//!!!!!!注意别忘记放Data!!!!!!!!!
NewNode->Data = X;
List = NewNode;
return List;
//以上两句可以写成一个return NewNode;
}
//	找到index-1结点
PointerToNode PointerToIndex_1 = NULL;
PointerToIndex_1 = FindKthOfLinkedList_TeacherVersion(List, index - 1);
//!!!!!!!!!!思考不全面!!!!!!!!!!!!
//万一index-1不存在怎么办?
if (PointerToIndex_1 == NULL)
{
printf("index非法");
return NULL;
}
NewNode->Data = X;
//先挂上后面的
NewNode->Next = PointerToIndex_1->Next;
//再把NewNode挂上去
PointerToIndex_1->Next = NewNode;
return;
}
//认真写一下删除操作
LinkedList DeleteIndexthElementOfLinkedListTeacherVersion(int index, LinkedList List)
{
//(0)一定要记住常见的意外:-1 0 length-1 length length+1
//删除非法的元素(小于0或者大于Length-1)
//如果删除-1或者Length,怎么办?
//-1前一个是-2,可以归到PointerToIndex_1==NULL里
//删除length+1也是
//但是length前一个是length-1,是存在的
//判定一下PointerToIndex_1->Next=NULL,第index个结点不存在
//删除的是length-1的话
//PointerToIndex_1->Next=PointerToIndex->Next;(等于NULL)
//free,这是对的
//最后的一个意外就是删除的是0
//PointerToIndex_1 == NULL,但是可以删除
//综上所述:
// -1        PointerToIndex_1 == NULL,且不能删除(1)【A】
// 0         PointerToIndex_1 == NULL,但可以删除(2)【B】
// length-1  PointerToIndex_1 != NULL,且可以删除(3)【正常处理】
// length    PointerToIndex_1 != NULL,但不能删除(4)【C】
// length+1  PointerToIndex_1 == NULL,且不能删除(5)【A】
//【B】
if (index == 0)
{
PointerToNode tmp = List;
//!!还有一个小问题:空表
if (tmp == NULL)
{
return NULL;
}
List = List->Next;
//free,与malloc配对,
free(tmp);
return List;
}
//
PointerToNode PointerToIndex_1 = NULL;
PointerToIndex_1 = FindKthOfLinkedList_TeacherVersion(List,index-1);
//【A】
if (PointerToIndex_1 == NULL)
{
//只要是出错,就是return NULL;
return NULL;
}
//【C】
PointerToNode PointerToIndex = NULL;
//	PointerToIndex = FindKthOfLinkedList_TeacherVersion(List, index);可简化成下面那一句
PointerToIndex = PointerToIndex_1->Next;
if (PointerToIndex == NULL)
{
return NULL;
}
PointerToNode tmp = NULL;
tmp = PointerToIndex;
PointerToIndex_1->Next = PointerToIndex->Next;
free(tmp);
return List;

}


 

----------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------------------------------------

----------------------------------------------------------------------------------------------------------------------------------------

2)typedef struct 指针

3)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: