1、线性表合并(A∪B、不要求顺序)
①求出A、B长度
②从LB中第1个数据元素开始,循环n次执行以下操作:
从LB中查找第i(1≤i≤n)个数据元素赋给e;
在LA中查找元素e,如果不存在,则将e插在表LA的最后。
void MergeList(List &LA, List LB)
{ // 将所有在线性表LB中但不在LA中的数据元素插入LA中
m = ListLength(LA);
n = ListLength(LB); // 求线性表的长度for(i=l;i<=n;i++)
while (n--)
{
GetElem(LB, i, e); // 取LB中第i个数据元素赋给e
if (!LocateElem(LA, e)) // LA中不存在和e相同的数据元素
ListInsert(LA, ++m, e); // 将e插在LA的最后
}
}
表长LA=m LB=n 循环执行n次
顺序表:取值与插入时间与表长无关,查找与表长m成正比,算法复杂度为O(mxn)
链表:取值时间与表长n成正比,插入与查找和表长m成正比,假设m大于n,算法复杂度为O(mxn)
(A∩B算法类似、元素输出的次序按在集合A中出现的次序)
void MergeList(LinkList &LA, LinkList LB)
{ // 将所有在线性表LA中但不在LB中的数据元素删除
int m,n,e;
m = ListLength(LA);
n = ListLength(LB);
int i = 1;
while (m--)
{
GetElem(LA, i, e); // 取LA中第i个数据元素赋给e
if (!LocateElem(LB, e)) // LB中不存在和e相同的数据元素
ListDelete(LA, i); // 删除该元素
else i++;
}
}
2、有序表合并
1)顺序有序表合并
创建空表LC、比较LA、LB元素摘取到LC最后,直至LA、LB其中一表为空。对比剩余元素插入LC。
①创建一个表长为m+n的空表LC
②指针pc初始化指向LC第一个元素
③指针pa、pb初始化,分别指向LA、LB第一个元素
④当指针pa、pb未到表尾时依次比较二者所指向元素值,摘取元素值小的节点插入LC最后
⑤如果pb已到达LB表尾,依次将LA剩余元素插入LC最后
⑥如果pa已到达LA表尾,依次将LB剩余元素插入LC最后
void MergeList_Sq(SqList LA, SqList LB, SqList &LC)
{
pa = LA.elem;
pb = LB.elem; // 指针pa和pb的初值分别指向两个表的第一个元素
LC.length = LA.length + LB.length; // 新表长度为待合并两表的长度之和
LC.elem = new ElemType[LC.length]; // 为合并后的新表分配一个数组空间
pc = LC.elem; // 指针pc指向新表的第一个元素
pa_last = LA.elem + LA.length - 1; // 指针pa_last指向LA表的最后一个元素
pb_last = LB.elem + LB.length - 1; // 指针pb_last指向LB表的最后一个元素
while (pa <= pa_ last &&pb < = pb_ last)
{
// 两个表都非空
if (*pa <= *pb)
*pc++ = *pa++;
// 依次“摘取”两表中值较小的结点
else
*pc++ = *pb++;
}
while (pa <= pa_ last)
*pc++ = *pa++; // LB表已到达表尾, 将LA中剩余元素加入LC
while (pb <= pb_ last)
*pc + += *pb + +; // LA表已到达表尾,将LB中剩余元素加入LC
} // MergeList_ Sq
算法的时间复杂度是: O(ListLength(La)+ ListLength(Lb))
算法的空间复杂度是: O(ListLength(La) + ListLength(Lb))
*利用链表实现上述操作,不需要开辟新的存储空间,可以使空间复杂度降到最低
2)链式有序表合并
①指针pa、pb初始化,分别指向LA、LB第一个结点
②LC结点取值为LA头结点
③pc指针初始化指向LC头结点
④当指针pa、pb未到表尾时依次比较二者所指向元素值,摘取元素值小的节点插入LC最后
⑤将非空表剩余段插入pc所指结点后
⑥释放LB头结点
void MergeList_ L(LinkList &la, LinkList &Lb, LinkList &Lc)
{
pa = La->next;
pb = Lb->next;
pc = Lc = La;
// 用La的头结点作为Lc的头结点
while (pa && pb)
{
if (pa->data < = pb->data)
{
pc->next = pa;
pc = pa;
pa = pa->next;
}
else
{
pc->next = pb;
pc = pb;
pb = pb->next;
}
}
pc->next = pa ? pa : pb; // 插入剩余段
delete Lb;
// 释放Lb的头结点
}
算法的时间复杂度是: O(ListLength(La)+ ListLength(Lb))
算法的空间复杂度是: O(1)
3、多项式运算
利用数组p表示:数组中每个分量p[i]表示多项式每项的系数pi,数组分量的下标i即对应
项的指数。数组中非零的分量个数即多项式的项数。
两个多项式运算:
●创建一个新数组c
●分别从头遍历比较a和b的每一项
指数相同,对应系数相加,若其和不为零,则在c中增加一一个新项
指数不相同,则将指数较小的项复制到c中
●一个多项式已遍历完毕时,将另一一个剩余项依次复制到c中即可
*顺序存储结构存在问题:存储空间分配不灵活、运算的空间复杂度高
链式存储结构
typedef struct PNode
{
float coef; // 系数
int expn;// 指数
struct PNode *next; // 指针域
} PNode, *Polynomial;
链表-多项式创建:
多项式的创建方法类似于链表的创建方法,区别在于多项式链表是一个有序表,每项的位置要经过比较才能确定。首先初始化一个空链表用来表示多项式,然后逐个输入各项,通过比较,找到第一个大于该输人项指数的项,将输人项插到此项的前面,这样即可保证多项式链表的有序性。
1、创建一个只有头节点的空链表。
2、根据多项式的项的个数n,循环n次执行以下操作:
①生成一个新节点*s;
②输入多项式当前项的系数和指数赋给新节点*s的数据域;
③设置一前驱指针pre,用于指向待找到的第一个大于输入项指数的节点的前驱,pre初始时指向头节点;
④指针q初始化,指向首元节点;
⑤循环向下逐个比较链表中当前节点中的值与输入项指数,找到第一个值大于输入项指数的节点*q;
⑥将输入项节点*s插入*q和其前驱节点pre之间。
void CreatePolyn(Polynomial &P, int n)
{
// 输入m项的系数和指数,建立表示多项式的有序链表P
P = new PNode;
P->next = NULL;
// 先建立一个带头结点的单链表
for (i = 1; i <= n; ++i)
{
// 依次输入n个非零项
s = new PNode;
// 生成新结点
cin >> s->coef >> s->expn;
// 输入系数和指数
pre = P;
// pre用于保存q的前驱,初值为头结点
q = P->next;
// q初始化,指向首元结点
while (q && q->expn < s->expn)
{
// 找到第一一个大于输入项指数的项*q
pre = q;
q = q->next;
s->next = q; // 将输入项s插入到q和其前驱结点pre之间
pre->next = s;
}
}
}
时间复杂度:O(n^2)【循环输入n次*循环比较n次】
链表-多项式相加
①指针p1和p2初始化,分别指向Pa和Pb的首元结点。
②p3指向和多项式的当前结点,初值为Pa的头结点。
③当指针p1和p2均未到达相应表尾时,则循环比较p1和p2所指结点对应的指数值
(p1-> expn与p2->expn) 有下列3种情况:
当p1>expn= =p2-> expn时,则将两个结点中的系数相加
■若和不为零,则修改p1所指结点的系数值,同时删除p2所指结点
■若和为零,则删除p1和p2所指结点;
当p1->expn<p2-> expn时,则应摘取p1所指结点插入到和多项式"链表中去;
当pTxexpn>p2-> expn时,则应摘取p2所指结点插入到“和多项式"链表中去。
④将非空多项式的剩余段插入到p3所指结点之后。
⑤释放Pb的头结点。
void AddPolyn(Polynomial &Pa, Polynomial &Pb) // 多项式加法:Pa=Pa+Pb,利用两个多项式的节点构成“和多项式”
{
p1 = Pa->next;
p2 = Pb->next; // p1和p2初始时分别指向Pa和Pb的首元节点
p3 = Pa; // p3指向和多项式的当前节点,初值为Pa
while (p1 && p2) // p1和p2均非空
{
if (p1->expn == p2->expn)
{ // 指数相等
sum = p1->coef + p2->coef; // sum保存两项的系数和
if (sum != 0) // 系数和不为0
{
// 修改Pa当前指向节点的系数值为两项系数的和
p1->coef = sum;
p3->next = p1;
p3 = p1; // 将修改后的Pa当前指向节点链接在p3之后,p3指向p1
p1 = p1->next; // p1指向后一项
r = p2;
p2 = p2->next;
delete r; // 删除Pb当前指向节点,p2指向后一项
}
else
{
r = p1;
p1 = p1->next;
delete r; // 删除Pa当前指向节点,p1指向后一项
r = p2;
p2 = p2->next;
delete r; // 删除Pb当前指向节点,p2指向后一项
}
}
else if (p1->expn < p2->expn) // Pa当前指向节点的指数值小
{
p3->next = p1; // 将p1链接在p3之后
p3 = p1; // p3指向p1
p1 = p1->next; // p1指向后一项
}
else // Pb当前指向节点的指数值小
{ // 将p2链接在p3之后
p3->next = p2; // p3指向p2
p3 = p2; // p2指向后一项
P2 = p2->next;
}
} // while
p3->next = p1 ? p1 : p2; // 插人非空多项式的剩余段
delete Pb; // 释放Pb的头节点
}
图书信息管理系统存储结构
struct Book
{
char id[20]; // ISBN
char name[50]; // 书名
int price;//定价
};
typedef struct
{ // 顺序表
Book *elem;
int length;
} SqList;
typedef struct LNode
{ // 链表
Book data;
struct LNode *next;
} LNode, *LinkList;