一、概念及类型定义
1.特点:同一性、有穷性、有序性。
2.基本操作(除第一个以外其他操作初始条件均为线性表L已存在,且要注意有些i的取值范围不能超过L的长度)
InitList(&L) //构造一个空的线性表L
DestroyList(&L) //L已存在,销毁线性表L
ListEmpty(L)//线性表判空 L为空表返回1,反之0
ListLength(L) //返回L中元素个数
PriorElem(L, cur_e, &pre_e)
//求前驱 cur_e是L的元素且不是第一个,pre_e返回他的前驱
NextElem(L, cur_e, &next_e)
//求后继 cur_e是L的元素且不是最后一个,next_e返回他的后继
GetElem(L, i, &e)
//求某个数据元素;1<= i <= LengthList(L) e返回L中第i个元素的值
LocateElem(L, e)
//定位函数 e给定 返回L中第一个与e相等的元素的位序,不存在返回0
ListTraverse(L, visit())
//遍历 对每个元素调用visit()函数
SortList(&L)
//排序 按某一数据项的值对线性表中的元素进行排序
ClearList(&L)
//将L置为空表
ListInsert(&L, i, e)
//在L中第i个元素之前插入新的元素e,L长度增加i
ListDelete(&L, i, &e)
//删除L的第i个元素并用e返回其值,L长度减1
二、顺序表示和实现
1.用一组地址连续的存储单元依次存放线性表的各个数据元素。起始地址称为基地址。
2.静态数组定义顺序表:
#define MAXSIZE //数组可能的长度
typedef struct
{
ElemType elem[MAXSIZE]; //线性表占用的数组空间
int length; //线性表当前长度
}SqList;
3.动态分配存储空间 :
#define LIST_INIT_SIZE 100 //存储空间的初始分配量
#define LISTINCREMENT 10 //存储空间的分配增量
typedef struct
{
ElemType *elem //存储空间基址
int length; //当前长度
int listsize; //分配的存储容量
}SeqList
//动态分配存储空间的初始化函数 即构造一空表
Status InitList_Sq(SqList &L)
{
L.elem = (ElemType *) malloc(LIST_INIT_SIZE *sizeof(ElemType));
if(!L.elem) exit(OVERFLOW);
L.length = 0;
L.listsize = LIST_INIT_SIZE;
return OK;
}//InitList_Sq
4.查找算法
(1)按序号查找:GetData(L, i) = L.elem[i] 查找线性表L中第i个数据元素。
(2)按内容查找:Locate(L, e)
5.插入算法
(1)判断位置是否合法 :1<= i <= n+1
(2)需要从表尾到i逐个一次向右移动数据元素(n-i+1个元素):aj+i = aj j = n, n-1,...,i
(3)插入并修改表的长度 ai = x,n= n+1
Status ListInsert_Sq(Sqlist L,int i,ElemType e)
{ if (i<1 || i>L.length+1) return ERROR;
if (L.length>=L.listsize)//当前存储空间已满
{ newbase=(ElemType *) realloc(L.elem,
(L.listsize +LISTINCREMENT)*sizeof(ElemType));
if (!newbase) exit(OVERFLOW);//分配不成功
L.elem= newbase;
L.listsize += LISTINCREMENT; }
q=&(L.elem[i-1]); //q所指向的是第 i 个元素
for(p=&(L.elem[L.length-1]);p>=q;--p) //从最后一个元素移动
*(p+1)=*p;
*q=e;
++L.length;
return OK;
}//ListInsert_Sq
移动次数:n-i+1
6.删除算法
Status ListDelete_Sq(Sqlist &L,int i ,ElemType &e)
{ //在顺序表L中删除第i个元素,并用e返回其值
//i的合法值为1 <= i <= ListLength_Sq(L)
if((i<1) || (i>L.length)) return ERROR;
p=&(L.elem[i-1]);
e=*p;
q=&(L.elem [ L.length-1]);
for(++ p;p<= q;++p)
*(p-1)=*p;
- - L.length;
return OK;
}//ListDelete_Sq
移动次数:n-1
7.顺序存储结构优缺点
(1)方便存取;无需额外增加存储空间
(2)插入删除移动太多;只能预先静态分配
三、链式表示和实现
1.线性链表
(1)头指针head存放一个地址
每个结点:实际数据+下一个结点的地址
最后一个结点:指针域放一个NULL,链表结束
(2)单链表存储空间分配和释放:
//头文件:stdlib.h和alloc.h
//malloc函数
void *malloc(unsigned int size);
//free函数
void free(void *p);
LinkList s;//s是指针变量
s = (linklist) malloc(sizeof(LNode))//申请了一个结点空间
free(s)//适当s所指的结点
!!数据域(*s).data 或者s->data
!!指针域(*s).next 或者s->next
(3)单链表初始化:
//定义单链表
typedef struct LNode
{
ElemType data; //数据域,存储数据元素
struct LNode * next;
//指针域,记录后继结点的存储位置
} LNode, *LinkList;
//初始化单链表
LinkList init_linklist(LinkList L) //对带头结点
单链表进行初始化
{
L=(LinkList)malloc(sizeof(Node)); //申请空间
L->next=NULL; //置为空表
return L;
}
//销毁表DestroyList(L)
void DestroyList(LinkList L)
{
LinkList p=L, q=p->next;
while (q!=NULL)
{
free(p);
p=q;
q=p->next;
}
free(p);
}
(4)尾插法建立单链表
void CreateFromTail(LinkList L)
{ LNode *r, *s; char c; int flag=1; r=L;
while(flag)
{ c=getchar();
if(c!='$')
{ s=(LNode*)malloc(sizeof(LNode));
s->data=c;
r->next=s;
r=s;
}
else
{ flag=0;
r->next=NULL;
}
}
}
(5)头插法建单链表
void CreateFromHead(LinkList L)
{ LNode *s; char c; int flag=1;
while(flag)
{ c=getchar();
if(c!='$')
{ s=(LNode*)malloc(sizeof(LNode));
s->data=c;
s->next=L->next
L->next=s; }
else
flag=0;
}
}
(6)取元素
Status GetElem_L(LinkList L,int i ,ElemType &e)
{ //L为带头结点的单链表的头指针
p=L->next; j=1;
while( p && j<i)
{
p=p->next; ++j;
}
if (!p|| j>i) return ERROR; //第i个元素不存在
e = p->data;
return OK;
}//GetElem_L // 时间复杂度为O(n)
(7)插入结点:ListInsert(L, i, e)
Status ListInsert_L(LinkList &L, int i, ElemTyp e )
{ //在带头结点的单链表L中第i个位置之前插入元素e
p=L;j=0;
while (p && j<i-1) //当循环结束时p可能指向第i-1个元素
{
p=p->next;
++j;
}
if(!p || j>i-1) return ERROR;
s=(LinkList ) malloc(sizeof(LNode));
s->data=e; s->next=p->next; p->next=s;
return OK;
}//ListInsert_L
(8)删除结点:ListDelete(L, i, e)
Status ListDelete_L(Linklist &L, int i, ElemTyp &e )
/ /在带头结点单链表 L 上删除第i个结点,并由e返回其值
{ p=L;j=0;
while (p->next && j<i-1 )
{
p=p->next;++j;
}
if(!p->next || j>i-1 ) return ERROR;
q=p->next; p->next=q->next;
e=q->data; free(q);
return OK;
}//ListDelete_L
2.循环链表
表中最后一个结点后继是否为头结点
3.双向链表
每个节点的指针域里包含两个指针,一个指向前驱结点,一个指向后继结点。
4.链表存储的特点
(1)不用事先估计存储规模,但存储密度较低
(2)按序访问时间性能O(n)
(3)操作基于指针
四、一元多项式
见PPT