基本概念
线性表的基本操作
1.InitList(&L)
初始化表。构造一个空的线性表L,分配内存空间。
2.ListLength(L)
返回线性表L的长度,即L中数据元素的个数。
3.GetData(L,i)
按位查找。返回线性表L中第i个法元素的值,
4.InsList(&L,i,e)
在L中第i个位置之前插入新的数据元素e,L的长度加1。
因为要修改线性表L的具体内容,并且把修改的效果带回去,所以用&。
5.DelList(&L,i,&e)
删除L的第i个数据元素,并用e返回其值(即返回删除元素的值),L的长度减1。
6.Locate(L,e)
按值查找。如果L中存在数据元素e,则将当前指针指向数据元素e所在位置并返回true,否则返回false。
7.DestroyList(L)
将L销毁,释放线性表L所占内存空间。
8.ClearList(L)
将L置为空表。
9.EmptyList(L)
判空。返回true或false。
10.PrintList(L)
按前后顺序输出线性表L中的所有元素值。
清空链表和销毁链表的区别:
当清空所有数据的节点,并且释放头结点后,该链表就无法再通过头结点创建,访问,插入,删除节点,因此相当于销毁了此链表。
清空链表,不清空头结点,链表还是可以继续使用。从第一个有数据的节点开始释放。
销毁链表后,不能对链表进行任何操作,否则为访问权限冲突,因为头结点指向的内存的操作权限已经归还给了操作系统。
释放链表的节点,是将链表每个节点包括指针域和数据域的一块结构体所占据的内存的操作权限还给系统,即释放了该块内存。
顺序存储
顺序表:关系线性化,结点顺序存。
计算存储地址:loc(Ai)=loc(A1)+(i-1)*sizeof(ElemType)
loc(A1)为基地址,即第一个元素的地址。
查找
按序号查找参考 【顺序表的基本操作】顺序表的按位查找与按值查找
按序号查找
静态分配顺序表
#define MaxSize 10
typedef struct
{
int data[MaxSize]; //静态分配
int length;
}SqList;
int GetLem(SqList L,int i)
{
return L.data[i-1];
}
动态分配顺序表
#define InitSize 10
typedef struct
{
int *data; //动态分配
int MaxSize;
int length;
}SqList;
void InitList(SqList &L)
{
//用malloc函数申请一片连续的存储空间
L.data=(int *)malloc(InitSize*sizeof(int) );
L.length=0;
L.MaxSize=InitSize;
}
int GetLem(SqList L,int i)
{
return L.data[i-1]; //和访问普通数组方法一样
}
按内容查找
int Locate(SeqList L,ElemType e)
//在顺序表L中查找与e相等的元素,若L.elem[i]=e,则找到该元素,并返回i+1,若找不到,则返回-1
{
i=0; //i为扫描计数器,初值为0,即从第一个元素开始比较
while((i<=L.last)&&(L.elem[i]!=e)) //顺序扫描表,直到找到值为e的元素,或扫描到表尾而没找到
i++;
if(i<=L.last)
return i+1; //若找到值为e的元素,则返回其序号
else
return -1; //若没有找到,则返回空序号
}
插入
#define OK 1
#define ERROR 0
int InsList(SeqList *L,int i,ElemType e)
//在顺序表L中第i个数据元素之前插入一个元素e。i的合法取值范围是1<=i<=L->last+2
{
int k;
if((i<1)||(i>L->last+2)) //首先判断插入位置是否合法
{
printf("插入位置i值不合法");
return(ERROR);
}
if(L->last>=MAXSIZE-1)
{
printf("表已满,无法插入");
return(ERROR);
}
for(k=L->last;k>=i-1;k--) //为插入元素而移动位置
L->elem[k+1]=L->elem[k];
L->elem[i-1]=e;
L->last++;
return(OK);
}
删除
int DelList(SeqList *L,int i,ElemType *e)
//在顺序表L中删除第i个数据元素,并用指针参数e返回其值。i的合法取值为1<=i<=L.last+1
{
int k;
if((i<1)||(i>L->last+1))
{
printf("删除位置不合法!");
return(ERROR);
}
*e=L->elem[i-1]; //将删除的元素存放到e所指向的变量中
for(k=i;i<=L->last;k++)
L->elem[k-1]=L->elem[k]; //将后面的元素依次前移
L->last--;
return(OK);
}
合并
void mergeList(SeqList *LA,SeqList *LB,SeqList *LC)
{
int i,j,k,l;
i=0;
j=0;
k=0;
while(i<=LA->last&&j<=LB->last)
{
if(LA->elem[i]<=LB->elem[j])
{
LC->elem[k]=LA->elem[i];
i++;
k++;
}
else
{
LC->elem[k]=LB->elem[j];
j++;
k++;
}
}
while(i<=LA->last) //当表LA有剩余元素时,则将表LA余下的元素赋给表LC
{
LC->elem[k]=LA->elem[i];
i++;
k++;
}
while(j<=LB->last) //当表LB有剩余元素时,则将表LB余下的元素赋给表LC
{
LC->elem[k]=LB->elem[j];
j++;
k++;
}
LC->last=LA->last+LB->last+1;
}
链式存储
连接方式:单、双、循环
实现角度:动态、静态
单链表
typedef struct Node
{
ElemType data;//数据域
struct Node*next;//指针域
}Node,*LinkList;
//Node*强调返回的是一个结点,LinkList L强调这是一个单链表
1. 初始化
InitList(LinkList *L)
{
*L=(LinkList)malloc(sizeof(Node)); //建立头结点
(*L)->next=NULL; //建立空的单链表L
}
2.1 建立——头插法
void CreateFromHead(LinkList L)
//L是带头结点的空链表头指针,通过键盘输入表中元素值,利用头插法建单链表L
{
Node *s;
char c;
int flag=1;
while(flag) //flag初值为1,当输入“$”时,置flag为0,建表结束
{
c=getchar();
if(c!='$')
{
s=(Node*)malloc(sizeof(Node)); //建立新结点s
s->data=c;
s->next=L->next; //将s结点插入表头
L->next=s;
}
else
flag=0;
}
}
2.2 建立——尾插法
void CreateFromTail(LinkList L)
//L是带头结点的空链表头指针,通过键盘输入元素值,利用尾插法建单链表L
{
Node *r,*s;
int flag=1; //设置一个标志,初值为1,当输入"$"时,flag为0,建表结束
r=L; //r指针动态指向链表的当前表尾,以便于做尾插入,其初值指向头结点
while(flag) //循环输入表中元素值,将建立新结点s插入表尾
{
c=getchar();
if(c!='$')
{
s=(Node*)malloc(sizeof(Node));
s->data=c;
r->next=s;
r=s;
}
else
{
flag=0;
r->next=NULL; /将最后一个结点的next链域置为空,表是链表的结束
}
}
}
3.1 查找——按位
Node *Get(LinkList L,int i)
//在带头结点的单链表L中查找第i个结点,若找到(1<=i<=n),则返回该结点的存储位置;否则返回NULL
{
int j;
Node *p;
if(i<=0)
return NULL;
p=L;
j=0; //从头结点开始扫描
while((p->next!=NULL)&&(j<i))
{
p=p->next; //扫描下一结点
j++;
}
if(i==j)
return p; //找到了第i个结点
else
return NULL; //找不到,i<=0或i>n
}
3.2 查找——按值
Node *Locate(LinkList L,ElemType key)
//在带头结点的单链表L中查找其结点值等于key的第一个结点,若找到则返回该结点的位置p,否则返回NULL
{
Node *p;
p=L->next; //从表中第一个结点开始
while(p!=NULL) //当前表未查完
{
if(p->data!=key)
p=p->next;
else
break; //找到结点值=key时退出循环
}
return p;
}
4. 求单链表长度
int ListLength(LinkList L)
//求带头结点的单链表L的长度
{
Node *p;
p=L->next;
j=0; //用来存放单链表的长度
while(p!=NULL)
{
p=p->next;
j++;
}
return j; //j为求得的单链表长度
}
5. 插入
void InsList(LinkList,int i,ElemType e)
//在带头结点的单链表L中第i个位置插入值为e的新结点
{
Node *pre,*s;
int k;
if(i<=0)
return ERROR;
pre=L;
k=0; //从“头”开始,查找第i-1个结点
while(pre!=NULL&&k<i-1) //表未查完且未查到第i-1个时重复,找到pre指向第i-1个
{
pre=pre->next;
k=k+1;
}//查找第i-1个结点
if(pre==NULL) //如当前位置pre为空表示已找完,但还未数到第i个,说明插入位置不合理
{
printf("插入位置不合理!");
return ERROR;
}
s=(Node*)malloc(sizeof(Node)); //申请一个新的结点
s->data=e; //值e置入s的数据域
s->next=pre->next; //修改指针,完成插入操作
pre->next=s;
return OK;
}
6. 删除
int DelList(LinkList L,int i,ElemType *e)
//在带头结点的单链表L中删除第i个元素,并将删除的元素保存到变量*e中
{
Node *pre,*r;
int k;
pre=L;
k=0;
while(pre->next!=NULL&&k<i-1) //寻找被删除结点i的前驱结点i-1使p指向它
{
pre=pre->next;
k=k+1;
}//查找第i-1个结点
if(pre->next==NULL) //while循环是因为p->next=NULL或i<1而跳出的,因为pre->next为空,没有找到合法的前驱位置,说明删除位置i不合法
{
printf("删除结点的位置i不合理!");
return ERROR;
}
r=pre->next;
pre->next=r->next; //修改指针,删除结点r
*e=r->data;
free(r); //释放被删除的结点所占的内存空间
return OK;
}
7. 合并两个有序的单链表
LinkList MergeLinkList(LinkList LA,LinkList LB)
//将递增有序的单链表LA和LB合并成一个递增有序的单链表LC
{
Node *pa,*pb;
LinkList LC;
//将LC初始置空表。pa和pb分别指向两个单链表LA和LB中的第一个结点,r初值为LC且r始终指向LC的表尾
pa=LA->next;
pb=LB->next;
LC=LA;
LC->next=NULL;
r=LC;
//当两个表中均未处理完时,比较选择将较小值结点插入到新表LC中。
while(pa!=NULL&&pb!=NULL)
{
if(pb->data<=pb->data)
{
r->next=pa;
r=pa;
pa=pa->next;
}
else
{
r->next=pb;
r=pb;
pb=pb->next;
}
}
if(pa) //若表LA未完,将表LA中后续元素链到新表LC表尾
r->next=pa;
else //否则将表LB中后续元素链到新表LC表尾
r->next=pb;
free(LB);
return(LC);
}
循环链表
基本操作
两种合并算法
//此算法将两个采用头指针的循环单链表的首尾连接起来
LinkList merge_1(LinkList LA,LinkList LB)
{
Node *p,*q;
p=LA;
q=LB;
while(p->next!=LA)
p=p->next; //找到表LA的表尾,用p指向它
while(q->next!=LB)
q=q->next; //找到表LB的表尾,用q指向它
q->next=LA; //修改表LB的尾指针,使之指向表LA的头结点
p->next=LB->next; //修改表LA的尾指针,使之指向表LB中的第一个结点
free(LB);
return(LA);
}
//此算法将两个采用尾指针的循环链表首尾连接起来
LinkList merge_2(LinkList RA,LinkList RB)
{
Node *p;
p=RA->next; //保存链表RA的头结点地址
RA->next=RB->next->next; //链表RB的开始结点链到链表RA的终端结点之后
free(RB->next); //释放链表RB的头结点
RB->next=p; //链表RA的开始结点链到链表RB的终端结点之后
return RB; //返回新循环链表的尾指针
}
双向链表
typedef struct DNode
{
ElemType data;
struct DNode *prior,*next;
}DNode,*DoubleList;
//前插(插入)操作
//删除
静态链表
#define MaxSize 10//链表可能达到的最大长度
typedef struct
{
ElemType data;
int cursor;
}Component,StaticList[MaxSize];
//初始化
//分配结点空间
一元多项式的表示及相加
1.一元多项式的表示
2.一元多项式的存储
//顺序存储
//链式存储
typedef struct Polynode
{
int coef;//系数
int exp;//指数
struct Polynode *next;
}Polynode,*Polylist;
//建立(尾插法)
3.一元多项式的相加运算