c语言建立线性表(顺序储存,链式储存,循环,双向)全
c語言建立線性表
- 順序儲存
- 儲存結構
- 初始化(建立)順序表
- 查找操作
- 一、按值查找,找到返回對應的下標
- 二、按照下標返回元素
- 插入操作
- 一、在線性表尾部添加元素
- 二、在位置i處插入元素
- 三、順序表(有序)插入,(如都是由小到大)
- 刪除操作
- 一、刪除位置i的元素,刪除成功后,返回刪除的值
- 二、刪除值為val的第一個元素,沒有返回-1
- 三、在非遞減有序的有序表中刪除多余的相同元素
- 其余操作
- 一、將線性表中的所有元素轉置
- 二、兩個有序的順序表合并后任然有序
- 完整代碼
- 鏈式儲存
- 存儲結構
- 建立鏈表
- 一、尾插法建立
- 二、頭插法建立
- 查找位置i的兩種方法
- 鏈表的查找操作
- 一、在鏈表中查找第i的節點
- 二、在單鏈表中按值查找第一個與val相等的節點
- 三、查找與val值相等的節點個數
- 四、找鏈表中的最大值與最小值
- 插入操作
- 一、在位置i前插入數據val
- 二、在位置i后插入數據val
- 三、在第一個值為val的后邊添加值val1
- 刪除操作
- 鏈表逆置
- 合并兩個有序表
- 完整代碼
- 循環鏈表
- 雙向鏈表
- 儲存結構
- 建立雙向鏈表
- 插入操作
- 刪除操作
- 其余操作
順序儲存
儲存結構
采用的是用內存動態分配方式定義線性表的順序儲存結構
#define LIST_MAX_SIZE 100 //線性表的最大長度 #define LISTINCREMENT 10 //線性表一次增加的量typedef struct {int* elem; //指向存放線性表數據元素的基地址int length; //線性表當前長度(當前存儲的元素個數)int listsize; // 當前分配的存儲容量 }SQList;初始化(建立)順序表
操作步驟:
查找操作
一、按值查找,找到返回對應的下標
一、按值查找,找到返回對應的下標,沒有則返回-1。如果有多個返回第一個的位置
條件:1、線性表存在;2、線性表中有元素
算法:在條件滿足的情況下,遍歷一遍,如果下標在i~length之間就返回下標
int ListLocate(SQList L, int e) {if (!L.elem ) {printf("線性表沒有初始化\n");return -1;}if (L.length == 0) {printf("線性表中沒有元素\n");return -1;}int i = 1;//下標是從1開始存儲元素的while (i <= L.length && e != L.elem[i])i++;if (i <= L.length) {printf("元素已經找到\n");return i;}else {printf("線性表中沒有該元素\n");return -1;} }二、按照下標返回元素
條件:1、線性表存在;2、下表沒有越界
int GetList(SQList L,int i) {if (!L.elem) {printf("線性表沒有初始化\n");return -1;}if (i<1 || i>L.length) {printf("數組下標越界\n");return -1;}return L.elem[i]; }插入操作
插入步驟,在后邊一定要將 length 加1一、在線性表尾部添加元素
條件:線性表存在
在條件滿足情況下:L.elem[++L.length] = val; 表示在尾部添加元素
void ListPush(SQList& L,int val) {if (!L.elem) {printf("線性表沒有初始化\n");return ;}if (L.length == L.listsize)//當前存儲空間已經滿了,增加分量{//在原來基礎上擴大int* newbase = (int*)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(int));if (!newbase) {printf("分配空間錯誤\n");return;}L.elem = newbase; //獲得新基址L.listsize += LISTINCREMENT;//更新容量}//在尾部插入L.elem[++L.length] = val; }二、在位置i處插入元素
步驟:
三、順序表(有序)插入,(如都是由小到大)
基本思路是:
先找到值val插入的位置。
然后將該位置以后到結尾的元素依次向后移到一位,然后在空出的位置插入val
刪除操作
插入步驟,在后邊一定要將 length 減1一、刪除位置i的元素,刪除成功后,返回刪除的值
兩種情況一個是在尾部,另一個是其余位置。 如果是在結尾只要length減一就可以了。
條件:添加 i不能越界
基本步驟:
二、刪除值為val的第一個元素,沒有返回-1
int ListDelete_Sq(SQList& L, int val) {//找到元素在的位置int i = 1;while (i <= L.length && val != L.elem[i])i++;//分情況刪除if (i == L.length)L.length--;else if (i < L.length) {//元素前移for (; i < L.length; ++i)L.elem[i] = L.elem[i + 1];L.length--;}else{printf("要刪除的數據元素不存在\n");return -1;} }三、在非遞減有序的有序表中刪除多余的相同元素
基本思路是:
因為是有序的所有相同元素一定是相鄰的,所有只要依次比較相鄰的元素,刪去相同的。
void Listdelete_Sq(SQList& L) {int i = 1;while (i < L.length) {if (L.elem[i] != L.elem[i + 1])i++;else { //刪除 第i+1個元素if (i == L.length - 1)L.length--;else {for (int j = i + 1; j < L.length; j++)L.elem[j] = L.elem[j + 1];//刪除第i個元素L.length--;//長度減一}}} }其余操作
一、將線性表中的所有元素轉置
void reverse_Sq(SQList& L) {int i = 1, j = L.length;while (i < j){int temp = L.elem[i];L.elem[i] = L.elem[j];L.elem[j] = temp;i++, j--;} }二、兩個有序的順序表合并后任然有序
思路是:
取出第一個邊和第二個表中最小的數據,兩者比較,將最小的插入到第三個表中,重復上述步驟。直到有一個表為空。然后繼續將不為空的表中的元素依次插入到第三個表中。
SQList MergeList_Sq(SQList La, SQList Lb) {SQList Lc;Lc.listsize = Lc.length = La.length + Lb.length;Lc.elem = (int*)malloc(Lc.listsize * sizeof(int));int i, j, k;i = j = k = 1;while (i <= La.length && j <= Lb.length) {if (La.elem[i] <= Lb.elem[j])Lc.elem[k++] = La.elem[i++];elseLc.elem[k++] = Lb.elem[j++];}while(i<=La.length)Lc.elem[k++] = La.elem[i++];while(j<=Lb.length)Lc.elem[k++] = Lb.elem[j++];return Lc; }完整代碼
#include<stdio.h> #include<malloc.h>#define LIST_MAX_SIZE 100 //線性表的最大長度 #define LISTINCREMENT 10 //線性表一次增加的量typedef struct {int* elem; //指向存放線性表數據元素的基地址int length; //線性表當前長度(當前存儲的元素個數)int listsize; // 當前分配的存儲容量 }SQList;//創建一個線性表 //注意點是:如果無法分配空間,打印提示,并直接返回 void CreateList(SQList &L) {L.elem = (int *)malloc(LIST_MAX_SIZE * sizeof(int));if (!L.elem) {printf("分配地址出錯\n");return;}L.length = 0;L.listsize = LIST_MAX_SIZE; }//求線性表中的元素個數 int ListLength(SQList L) {return L.length; }//增加容量 void increte_List(SQList& L) {//在原來基礎上擴大int* newbase = (int*)realloc(L.elem, (L.listsize + LISTINCREMENT) * sizeof(int));if (!newbase) {printf("分配空間錯誤\n");return;}L.elem = newbase; //獲得新基址L.listsize += LISTINCREMENT;//更新容量 }/* 查找操作*/ //一、按值查找,找到返回對應的下標,沒有則返回-1。如果有多個返回第一個的位置 //條件:1、線性表存在;2、線性表中有元素int ListLocate(SQList L, int e) {if (!L.elem ) {printf("線性表沒有初始化\n");return -1;}if (L.length == 0) {printf("線性表中沒有元素\n");return -1;}int i = 1;//下標是從1開始存儲元素的while (i <= L.length && e != L.elem[i])i++;if (i <= L.length) {printf("元素已經找到\n");return i;}else {printf("線性表中沒有該元素\n");return -1;} }//二、按照下標返回元素 //條件:1、線性表存在;2、下表沒有越界int GetList(SQList L,int i) {if (!L.elem) {printf("線性表沒有初始化\n");return -1;}if (i<1 || i>L.length) {printf("數組下標越界\n");return -1;}return L.elem[i]; }/* 插入元素*/ //一、在線性表尾部添加元素 //條件:線性表存在 void ListPush(SQList& L,int val) {if (!L.elem) {printf("線性表沒有初始化\n");return ;}if (L.length == L.listsize)//當前存儲空間已經滿了,增加分量increte_List(L);//在尾部插入L.elem[++L.length] = val; }//二、在位置i處插入元素 void ListInsert(SQList& L, int i, int val) {if (!L.elem) {printf("線性表沒有初始化\n");return;}if (L.length == L.listsize)//當前存儲空間已經滿了,增加分量increte_List(L);for (int j = L.length; j >= i; --j) {L.elem[j + 1] = L.elem[j]; //i后面的元素后移}//插入元素L.elem[i] = val;L.length++; }//三、順序表(有序)插入,(如都是由小到大) void ListInsertorder(SQList& L, int val) {if (!L.elem) {printf("線性表沒有初始化\n");return;}if (L.length == L.listsize)//當前存儲空間已經滿了,增加分量increte_List(L);//找到要插入的位置int pos = L.length;while (pos > 0 && val < L.elem[pos])pos--;//這個循壞結束后,POS對應位置元素是小于等于val的,所以可以將val插到其后邊for (int i = L.length; i >= pos+1; i--)L.elem[i + 1] = L.elem[i];//插入L.elem[pos + 1] = val;L.length++; }/* 刪除操作*/ // 一、刪除位置i的元素,刪除成功后,返回刪除的值 // 兩種情況一個是在尾部,另一個是其余位置 //添加 i不能越界 int ListDelete(SQList& L, int i) {if (!L.elem) {printf("線性表沒有初始化\n");return -1;}if (i<1 || i>L.length) {printf("數組越界\n");return -1;}int val = L.elem[i];if (i == L.length)L.length--;else{//元素往前移for (; i < L.length; i++)L.elem[i] = L.elem[i + 1];L.length--;}return val; }//二、刪除值為val的第一個元素,沒有返回-1int ListDelete_Sq(SQList& L, int val) {//找到元素在的位置int i = 1;while (i <= L.length && val != L.elem[i])i++;//分情況刪除if (i == L.length)L.length--;else if (i < L.length) {//元素前移for (; i < L.length; ++i)L.elem[i] = L.elem[i + 1];L.length--;}else{printf("要刪除的數據元素不存在\n");return -1;} }//三、在非遞減有序的有序表中刪除多余的相同元素 void Listdelete_Sq(SQList& L) {int i = 1;while (i < L.length) {if (L.elem[i] != L.elem[i + 1])i++;else { //刪除 第i+1個元素if (i == L.length - 1)L.length--;else {for (int j = i + 1; j < L.length; j++)L.elem[j] = L.elem[j + 1];//刪除第i個元素L.length--;//長度減一}}} }/*其余操作*/ //一、將線性表中的所有元素轉置void reverse_Sq(SQList& L) {int i = 1, j = L.length;while (i < j){int temp = L.elem[i];L.elem[i] = L.elem[j];L.elem[j] = temp;i++, j--;} }//二、兩個有序的順序表合并后任然有序 SQList MergeList_Sq(SQList La, SQList Lb) {SQList Lc;Lc.listsize = Lc.length = La.length + Lb.length;Lc.elem = (int*)malloc(Lc.listsize * sizeof(int));int i, j, k;i = j = k = 1;while (i <= La.length && j <= Lb.length) {if (La.elem[i] <= Lb.elem[j])Lc.elem[k++] = La.elem[i++];elseLc.elem[k++] = Lb.elem[j++];}while(i<=La.length)Lc.elem[k++] = La.elem[i++];while(j<=Lb.length)Lc.elem[k++] = Lb.elem[j++];return Lc; }void show(SQList L) {for (int i = 1; i <= L.length; ++i)printf("%d ", L.elem[i]);printf("\n"); }int main() {SQList La, Lb,Lc;CreateList(La);CreateList(Lb);for (int i = 1; i <= 5; ++i){int x;scanf_s("%d", &x);ListPush(La, x);}for (int i = 1; i <= 5; ++i){int x;scanf_s("%d", &x);ListPush(Lb, x);}show(La), show(Lb);reverse_Sq(Lb);show(Lb);Lc = MergeList_Sq(La, Lb);show(Lc);return 0; }鏈式儲存
存儲結構
typedef struct LNode {int date;LNode* next; }LNode;建立鏈表
一、尾插法建立
,需要建立三個指針,一個指向頭指針,一個始終指向尾部,一個指向新建立的
基本思路是:
為頭節點申請空間后,讓s也指向頭結點。然后為p申請空間并賦值,將s的下一個指針指向p,然后指針s后移。(即將p賦給s),重復這個步驟
LNode* create_E(int n) {LNode* head, * s,*p;head = (LNode *)malloc(sizeof(LNode));head->next = NULL;s = head;while (n--) {p = (LNode*)malloc(sizeof(LNode));scanf_s("%d", &p->date);s->next = p; //把新節點插入鏈表的結尾s = p; //指針s后移}s->next = NULL;return head; }二、頭插法建立
核心思路:
在頭結點后插入新節點。理解好這句。
我們要在頭結點后邊插入新節點,要什么做呢?首先是將原本頭結點的next放到新建立的節點的next把,然后再講頭結點的next指向p。
查找位置i的兩種方法
1、在i滿足1<=i<=length 的情況下一直往后移動i次就可以了。
LNode* p = head->next;int len = GetLength(head);if (i > len||i<1) {printf("i值不合理\n");return -1;}while (--i) {p = p->next;}因為在這里 p初值是 head->next 所以只要移動i-1次就到位置i了,所以是while(–i),如果是p初值是 head,則是 i–
2、
LNode* p, * s;p = head; //賦值是頭結點,不是nextint j = 0;while (p && j < i ) { //找第i個位置p = p->next;j++;}if (!p || j > i) //對應的情況是i超過長度,與i小于0{printf("i不合理\n");return;}鏈表的查找操作
一、在鏈表中查找第i的節點
//需要檢測 i的值是否合理int GetElem(LNode* head,int i) {LNode* p = head->next;int len = GetLength(head);if (i > len||i<1) {printf("i值不合理\n");return -1;}while (--i) {p = p->next;}return p->date; }二、在單鏈表中按值查找第一個與val相等的節點
int LocateElem(LNode* head,int val) {int i = 1;LNode* p = head->next;if (!p){printf("當前鏈表為空\n");return -1;}while (p && p->date != val) {p = p->next;i++;}//printf("位置i為:%d", i);if (i > GetLength(head)){printf("當前鏈表中沒有該值\n");return -1;}elsereturn i;}三、查找與val值相等的節點個數
int findnum(LNode* head,int val) {LNode* p = head->next;int num = 0;while (p) {if (p->date == val)num++;p = p->next;}return num; }四、找鏈表中的最大值與最小值
void find_max_min(LNode* head) {LNode* p = head->next;int Max = p->date, Min = p->date;while (p) {if (p->date > Max)Max = p->date;elseMin = p->date;p = p->next;}printf("最大值是:%d 最小值是:%d\n", Max, Min); }插入操作
一、在位置i前插入數據val
void ListInsert_P(LNode* head, int i, int val) {LNode* p, * s;p = head; //賦值是頭結點,不是nextint j = 0;while (p && j < i - 1) { //找第i-1個位置p = p->next;j++;}if (!p || j > i - 1) //對應的情況是i超過長度,與i小于1return;else{s = (LNode*)malloc(sizeof(LNode));s->date = val;s->next = p->next;p->next = s;} }二、在位置i后插入數據val
//第0個就是在頭結點后邊 void ListInsert_N(LNode* head, int i, int val) {LNode* p, * s;p = head; //賦值是頭結點,不是nextint j = 0;while (p && j < i ) { //找第i個位置p = p->next;j++;}//printf("j: %d\n", j);if (!p || j > i) //對應的情況是i超過長度,與i小于0{printf("i不合理\n");return;}else{s = (LNode*)malloc(sizeof(LNode));s->date = val;s->next = p->next;p->next = s;} }三、在第一個值為val的后邊添加值val1
void ListInsert_V(LNode* head, int val, int val1) {int i = LocateElem(head, val);//找到值val對應的位置//printf("位置i為:%d", i);ListInsert_N(head, i, val1); }刪除操作
int ListDelete(LNode* head, int i) {LNode* p, * q;int val;p = head;int j = 0;while (p->next && j > i - 1) {p = p->next;j++;}if (!p->next || j > i - 1)return -1;else{q = p->next;p->next = q->next;val = q->date;free(q);//釋放刪除的節點}return val; }鏈表逆置
void List_reverse(LNode* head) {LNode* p, * pre,*temp;pre = NULL;p = head->next;while (p) {temp = p->next;p->next = pre;pre = p;p = temp;}head->next = pre; //pre指向的是原來鏈表的終點 }合并兩個有序表
LNode* MargeList(LNode* head1, LNode* head2) {LNode* Lc,*La,*Lb,*head;head = (LNode*)malloc(sizeof(LNode));head->next = NULL;Lc = head;La = head1->next;Lb = head2->next;while (La && Lb) {if (La->date <= Lb->date){Lc->next = La;Lc = La; //記得后移La = La->next;}else{Lc->next = Lb;Lc = Lb;Lb = Lb->next;}}Lc->next = La ? La : Lb;return head; }完整代碼
#include<stdio.h> #include<malloc.h>typedef struct LNode {int date;LNode* next; }LNode;/* 建立鏈表*/ //一、尾插法建立,需要建立三個指針 //一個指向頭指針,一個始終指向尾部,一個指向新建立的 LNode* create_E(int n) {LNode* head, * s,*p;head = (LNode *)malloc(sizeof(LNode));head->next = NULL;s = head;while (n--) {p = (LNode*)malloc(sizeof(LNode));scanf_s("%d", &p->date);s->next = p; //把新節點插入鏈表的結尾s = p; //指針s后移}s->next = NULL;return head; }//二、頭插法建立 //只需要兩個指針 LNode* create_H(int n) { //得到的鏈表與輸入的值相反LNode* head, * p;head = (LNode*)malloc(sizeof(LNode));head->next = NULL;while (n--) {p = (LNode*)malloc(sizeof(LNode));scanf_s("%d", &p->date);p->next = head->next; //在頭結點后插入新節點head->next = p;}return head; }/*求鏈表的長度*/ int GetLength(LNode* head) {LNode* p = head->next;int len = 0;while (p) {p = p->next;len++;}return len; }/*鏈表的查找*/ //一、在鏈表中查找第i的節點 //需要檢測 i的值是否合理int GetElem(LNode* head,int i) {LNode* p = head->next;int len = GetLength(head);if (i > len||i<1) {printf("i值不合理\n");return -1;}while (--i) {p = p->next;}return p->date; }//二、在單鏈表中按值查找第一個與val相等的節點 int LocateElem(LNode* head,int val) {int i = 1;LNode* p = head->next;if (!p){printf("當前鏈表為空\n");return -1;}while (p && p->date != val) {p = p->next;i++;}//printf("位置i為:%d", i);if (i > GetLength(head)){printf("當前鏈表中沒有該值\n");return -1;}elsereturn i;} // 三、查找與val值相等的節點個數 int findnum(LNode* head,int val) {LNode* p = head->next;int num = 0;while (p) {if (p->date == val)num++;p = p->next;}return num; }//四、找鏈表中的最大值與最小值 void find_max_min(LNode* head) {LNode* p = head->next;int Max = p->date, Min = p->date;while (p) {if (p->date > Max)Max = p->date;elseMin = p->date;p = p->next;}printf("最大值是:%d 最小值是:%d\n", Max, Min); }/*插入操作*/ //一、在位置i前插入數據valvoid ListInsert_P(LNode* head, int i, int val) {LNode* p, * s;p = head; //賦值是頭結點,不是nextint j = 0;while (p && j < i - 1) { //找第i-1個位置p = p->next;j++;}if (!p || j > i - 1) //對應的情況是i超過長度,與i小于1return;else{s = (LNode*)malloc(sizeof(LNode));s->date = val;s->next = p->next;p->next = s;} }//二、在位置i后插入數據val //第0個就是在頭結點后邊 void ListInsert_N(LNode* head, int i, int val) {LNode* p, * s;p = head; //賦值是頭結點,不是nextint j = 0;while (p && j < i ) { //找第i個位置p = p->next;j++;}//printf("j: %d\n", j);if (!p || j > i) //對應的情況是i超過長度,與i小于0{printf("i不合理\n");return;}else{s = (LNode*)malloc(sizeof(LNode));s->date = val;s->next = p->next;p->next = s;} }//三、在第一個值為val的后邊添加值val1 void ListInsert_V(LNode* head, int val, int val1) {int i = LocateElem(head, val);//找到值val對應的位置//printf("位置i為:%d", i);ListInsert_N(head, i, val1); }/*刪除操作*/ //一、刪除位置i的節點,并返回刪除節點的值int ListDelete(LNode* head, int i) {LNode* p, * q;int val;p = head;int j = 0;while (p->next && j > i - 1) {p = p->next;j++;}if (!p->next || j > i - 1)return -1;else{q = p->next;p->next = q->next;val = q->date;free(q);//釋放刪除的節點}return val; }/*鏈表逆置*/ void List_reverse(LNode* head) {LNode* p, * pre,*temp;pre = NULL;p = head->next;while (p) {temp = p->next;p->next = pre;pre = p;p = temp;}head->next = pre; //pre指向的是原來鏈表的終點 }/*合并兩個有序表*/ LNode* MargeList(LNode* head1, LNode* head2) {LNode* Lc,*La,*Lb,*head;head = (LNode*)malloc(sizeof(LNode));head->next = NULL;Lc = head;La = head1->next;Lb = head2->next;while (La && Lb) {if (La->date <= Lb->date){Lc->next = La;Lc = La; //記得后移La = La->next;}else{Lc->next = Lb;Lc = Lb;Lb = Lb->next;}}Lc->next = La ? La : Lb;return head; }void show(LNode* head) {LNode* p = head->next;while (p) {printf("%d ", p->date);p = p->next;}printf("\n"); }int main() {LNode* head1,*head2,*head;head1 = create_E(5);show(head1);/*head2 = create_H(5);show(head2);List_reverse(head2);show(head2);head = MargeList(head1, head2);show(head);*/ListInsert_V(head1, 3, 8);show(head1);ListInsert_P(head1, 3, 47);show(head1);return 0; }循環鏈表
- 簡單來說就是將原本最后一個結點的指針域由空指針指向頭結點。
- 最后一個結點的語句是:p->next == head
雙向鏈表
儲存結構
/*雙向鏈表*/ typedef struct Node {int date;Node* prior;Node* next; }DuLinkList;建立雙向鏈表
/*建立雙向鏈表*/ DuLinkList* create_DuL(int n) {DuLinkList* head, * p, * s;head = (DuLinkList*)malloc(sizeof(DuLinkList));head->next = NULL;head->prior = NULL;s = head;while (n--) {p = (DuLinkList*)malloc(sizeof(DuLinkList));scanf_s("%d", &p->date);s->next = p;p->prior = s;s = p;}s->next = NULL;return head; }插入操作
/*雙向鏈表的插入操作*/ void ListInsert_DuL(DuLinkList* head, int i, int val) {int len = Get_num(head);if (i<1 || i>len){printf("i不合法\n");return;}DuLinkList* p ,*s;s = (DuLinkList*)malloc(sizeof(DuLinkList));s->date = val;p = head;while (--i)//i-- 得到的是位置i的結點,p = p->next;//printf("p = %d\n", p->date);//循環結束后p指向的是i的前一個結點s->next = p->next;p->next->prior = s;p->next = s;s->prior = p; }刪除操作
/*雙向鏈表的刪除操作*/ int ListDelete_DuL(DuLinkList* head, int i) {int len = Get_num(head);if (i<1 || i>len){printf("i不合法\n");return -1;}DuLinkList* p;p = head;while (--i)p = p->next;//printf("p = %d\n", p->date);//循環結束后p指向的是i的前一個結點p = p->next; //為了簡便指向位置i的結點int val = p->date;p->prior->next = p->next;p->next->prior = p->prior;free(p);return val; }其余操作
/*雙向鏈表中結點個數(存有數據的)*/ int Get_num(DuLinkList* head) {DuLinkList* p = head->next;int num = 0;while (p != NULL) {p = p->next;num++;}//printf("num = %d\n", num);return num; }void show_DuL(DuLinkList* head) {DuLinkList* p = head->next;while (p) {printf("%d ", p->date);p = p->next;}printf("\n"); }總結
以上是生活随笔為你收集整理的c语言建立线性表(顺序储存,链式储存,循环,双向)全的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: POJ3522Slim Span(最大边
- 下一篇: 线性表的应用之多项式的表示与相加