问题:一元多项式及其运算,主要运算有:加减乘等…
一
元
多
项
式
前
n
项
和
S
n
:
∑
n
=
0
n
a
n
X
n
,
与
幂
级
数
∑
n
=
0
∞
a
n
X
n
不
同
,
幂
级
数
为
lim
n
→
+
∞
∑
n
=
0
n
a
n
X
n
一元多项式前n项和S_n:\sum_{n=0}^{n}a_nX^n,与幂级数\sum_{n=0}^{\infty}a_nX^n不同,幂级数为\lim_{n\rightarrow+\infty}\sum_{n=0}^{n}a_nX^n
一元多项式前n项和Sn:n=0∑nanXn,与幂级数n=0∑∞anXn不同,幂级数为n→+∞limn=0∑nanXn
1.怎么存储每项元素
2.怎么实现运算
实现1
顺序存储[数组].
P
1
=
1
+
4
x
+
7
x
3
P
2
=
4
+
8
x
2
+
6
x
4
P1 = 1+4x+7x^3\\P2 = 4 + 8x^2 +6x^4
P1=1+4x+7x3P2=4+8x2+6x4
Array’s index | 0 | 1 | 2 | 3 | 4 |
---|---|---|---|---|---|
P1’s array | 1 | 4 | 0 | 7 | 0 |
P2’s array | 4 | 0 | 8 | 0 | 6 |
这里实现加法逻辑
for(i,i<(p1.len>p2.len?p1.len:p2.len),i++) p3[i] = p1[i]+p2[i]
output:p3
实现2(实现1,存储了多余次数为0项,加法逻辑也做了多余操作,浪费了存储空间,也增加了加法逻辑的时间复杂度。)
改进为顺序结构体存储[结构体数组] struct struc_array{ int an,int x_param} 按x_param系数从小排列
P
1
=
1
+
4
x
+
7
x
3
−
11
x
6
P
2
=
4
+
8
x
2
−
6
x
4
−
10
x
5
P1 = 1+4x+7x^3-11x^6\\P2 = 4 + 8x^2 -6x^4 -10x^5
P1=1+4x+7x3−11x6P2=4+8x2−6x4−10x5
P1’s struct_array | (1,0) | (4,1) | (7,3) | (-11,6) | ||
---|---|---|---|---|---|---|
P2’s struct_array | (4,0) | (8,2) | (-6,4) | (-10,5) | ||
p3 | (5,0) | (4,1) | (8,2) | (7,3) | (-10,5) | (-11,6) |
实现加法逻辑:
int i = 0, j = 0,k = 0;
begin:循环
if(p1[i].x_param < p2[j].x_param) { p3[k++] = p1[i];i++;} //直接输出x系数小的项
else { p3[k] = p2[j] ; j++;k++;}//和p3[k++] common
if(p1[i].x_param == p2[j].x_param) {p3[k].an = p1[i].an+p2.[j].an;p3.x_param = p1[i].x_param;k++;i++;j++} //x系数相同项相加an
end
实现3:
链式存储一元多项式:
typedef struct polynomial_node{
int an;
int x_param;
struct polynomial_node *next;
}poly_node;
poly_node* newnode(int an = 0,int x_param = 0){
poly_node* temp_node = (poly_node*)malloc(sizeof(poly_node))
temp_node->an = an;
temp_node->x_param = x_param;
return temp_node;
}
加法实现逻辑与二相同
链表结点的连接顺序按x_param从小到大连接
循环判断p1链表当前结点与p2链表当前结点的x的指数大小,若相等则将an系数相加,p1当前结点指向下一结点,p2当前结点指向下一节点;若不相等则输出系数小的项,同时系数小的链表的当前结点指向下一结点。若有链表已便利完,则逐个输出另一链表剩余结点所存储的项。
一元多项式可以这样存储那么二元多项式呢
P ( x , y ) = 9 x 1 2 y 2 + 4 x 1 2 + 15 x 8 y 3 − 8 x 1 2 y + 3 x 2 P(x,y) = 9x^12y^2 +4x^12+15x^8y^3-8x^12y+3x^2 P(x,y)=9x12y2+4x12+15x8y3−8x12y+3x2
我们可以采取线性表存储数据(顺序表没两个单元为一个项的存储单位)或链表数据域中存储x,y\
那么将P(x,y)合并同类项则有
P ( x , y ) = ( 9 y 2 + 4 ) x 1 2 + ( 15 y 3 − y ) x 5 + 3 x 2 P(x,y) = (9y^2+4)x^12+(15y^3-y)x^5+3x^2 P(x,y)=(9y2+4)x12+(15y3−y)x5+3x2
这里我们也可采取另一种存储结构广义表(线性表的推广,称其为Lists,表中数据元素由union联合体组成可表示不同结构,故难以用顺序结构存储,常用链式存储结构,)[外链图片转存失败(img-w18er1mP-1568032452694)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1561276451735.png)]
typedef enum{Atom,List}ElemTag; //Atom(原子) ==0,list(表) ==1 typedef struct s_GLNode{ ElemTag union_tag; union{ AtomType data; //原子所存储的数据 struct s_GLNode *hp;//字表的头节点 }; struct s_GLNode *next;//GLList的next结点,即主链表 }GLNode,*GList;
[外链图片转存失败(img-uSuja80t-1568032452698)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1561277735539.png)]
多重链表:节点中的指针域会有多个,所以上述广义表就可已是一种多重链表,但广义表所有结点都为tag==0不能算多重链表了。
且包含两个指针域的不能算多重链表,如双向链表(*piror,*next)整个链表还是为一个链表
再由一个问题退出一种新的线性表的推广,十字链表
[外链图片转存失败(img-VPytcblt-1568032452704)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1561279052742.png)]
每一行,列都为一个带头节点的单向循环链表,即第一行和第一列的头节点都为同一个结点,那么二行二列也是,类比n行n列也是
[外链图片转存失败(img-Z2ISSoaE-1568032452709)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1561279239376.png)]
typedef enum{Head,Term}NodeTag; //结点类型0-head,1-term typedef struct s_MLLM{ //s_Multiple_LinkList_Matrix NodeTag tag; struct s_MLLM *Dowm;//列指针 union{ Row row; //Term结点所在的行 Col col; //列 Value value;//存储的值 struct s_MLLM *Next; //若为头节点则指向下一头节点 }; struct s_MLLM *Right;//行指针 }
[外链图片转存失败(img-fPXgPFCP-1568032452710)(C:\Users\lin\AppData\Roaming\Typora\typora-user-images\1561279617759.png)]
1.线性表(Linear List):由n个相同类型的数据元素构成的有限序列的线性结构。
1)表中元素的个数称为线性表的长度
2)表的起始位置为表头(唯一的第一个元素),表的结束位置为表尾(唯一的最后一个元素)
3)除第一个元素外只有一个前驱(表头无前驱),除最后一个元素外元素只有一个后继(表尾无后继)
2.线性表的常用存储存储方式
1)顺序存储(逻辑上相邻,物理上也相邻),线性表的顺序存储实现可称顺序表。
优点:可随机存取
缺点:插入,删除操作时需移动大量个元素。
2)链式存储(逻辑上相邻,但不要求物理上相邻),线性表的链式村粗实现可称链表 。
由n个结点链接而成,每个结点由值域和指针域组成
与顺序表相比,没有了随机存取的优点,同时没有了顺序表的缺点,链表插入,删除时只需修改前一结点指针域。
1.1)顺序表的定义和基本操作的实现
1.Sqlist使用一维数组静态分配,数组大小空间固定 #define Maxsize 10 typedef struct static_Sqlist{ ElemType data[Maxsize]; int length; }Sqlist; 2.Sqlist使用动态分配的一位数组 typedef struct dynamic_Sqlist{ ElemType *data; int length; }Sqlist; //初始化内存 Status init(Sqlist &list,int init_size){ list.data = (ElemType *)malloc(sizeof(ElemType)*init_size); list.length = init_size; } //申请更多内存 Status more(Sqlist &list,int more_size){ list.data = (ElemType *)remalloc(list.data,sizeof(ElemType)*more_size); list.length += more_size; }
1.2)插入操作实现
Status insert(Sqlist &list,int i,ElemType e){ if( i < 1 || i > list.length + 1)//插入位置第一个到最后一个元素的( 1<=i<=l.len+1) return Error; if( list.length >= list.size) return Error; for(int j = list.length; j >= i; j--){//移动 n-i+1个元素 循环执行j -i +1次 list.data[j] = list.data[j-1]; } list.length++; return Ok;
最好时间复杂度:O(1),在表尾插入(即 i = n+1,最后一个元素的后一位)不移动元素
最坏时间复杂度:O(n),在表头插入(即 i = 1 ,第一个元素位置),移动n-1+1,即n个元素。
平均时间复杂度: O(n)设每一位置插入平均概率P=1/n+1(n+1,为插入选择n+1个),累加每一种可能移动的元素个数。
T ( n ) = p ∑ i = 1 n + 1 ( n − i + 1 ) = 1 n + 1 [ n ( n + 1 ) − ( n + 1 + 1 ) ( n + 1 ) 2 + ( n + 1 ) ] = 1 n + 1 n ( n + 1 ) 2 = n 2 T(n)=p\sum_{i=1}^{n+1}(n-i+1)=\frac{1}{n+1}[n(n+1)-\frac{(n+1+1)(n+1)}{2}+(n+1)]=\frac{1}{n+1}\frac{n(n+1)}{2}=\frac{n}{2} T(n)=pi=1∑n+1(n−i+1)=n+11[n(n+1)−2(n+1+1)(n+1)+(n+1)]=n+112n(n+1)=2n
1.3)删除操作实现//i 表示删除的元素的序号(1,2,。。。) Status delete(Sqlist &list,int i,ElemType &e){ if(i < 1 || i > list.length) return Error; //删除是否合法 e = list.data[i-1]; for(int j = i;j < list.length; j++ ) //移动n-i元素 list.data[j-1] = list.data[j]; return Ok; }
最好时间复杂度:O(1),删除的元素为尾部元素,不需移动元素
最坏时间复杂度: O(n),删除的元素为第一个元素,需移动n-1个元素,T(n) = n-1,故O(n) = n
平均时间复杂度:O(n),删除位置范围(1<=i<=n),设平均插入概率P = 1/n;
T ( n ) = ∑ i = 1 n P ( n − i ) = P ∑ i = 1 n ( n − i ) = 1 n [ n 2 − n ( n + 1 ) 2 ] = n − 1 2 T(n) = \sum_{i=1}^{n}P(n-i) = P\sum_{i=1}^{n}(n-i)=\frac{1}{n}[n^2-\frac{n(n+1)}{2}]=\frac{n-1}{2} T(n)=i=1∑nP(n−i)=Pi=1∑n(n−i)=n1[n2−2n(n+1)]=2n−1
故平均时间复杂度为O(n).1.4按值查找(顺序查找)
int LoacteElem(Sqlist &list,ElemType e){ for(int i = 0; i < list.length; i++) if(e == list.data[i]) return i+1; //i为当前位置索引,当前位置则加1 return -1;//未找到 }
最好时间复杂度:O(1),判断第一个元素及所找元素。
最坏时间复杂度:O(n),最好一个元素为所找元素,判断次数 T(n) = n
平均时间复杂度:O(n), 查找到的平均概率1/n,T(n) = 1/n * (n+1)n/2 = (n+1)/2,故平均时间复杂度为O(n).
。链表未完。。