< 今日知识点 >
线性表
- 顺序存储
- 链式存储
·
·
·
—01 多项式的表示
- 方法1:用顺序储存结构直接表示,数组的下标表示相应的指数
但是在一些情况下会造成很大的空间浪费,如x3+x2000 ,显然这个多项式用方法1来表示要用到2001个数组空间,造成不必要的浪费
- 方法2:顺序储存结构表示非零项,即用结构数组中的两个分量来表示,空间大大节省了,同时也可以做到运算方便(关键是要按指数递降的方式储存)
- 相加过程: 从头开始比较两个多项式当前对应项的指数,指数高的一项进入新的结构数组中,如果指数相等,则对应系数相加。
- 方法3:链表结构储存非零项:链表中每个节点储存多项式中的一个非零项,包括系数和指数两个数据域以及一个指针域
**相加过程:**与前面两个方法的思想是一样的。
·
·
·
—02 线性表
1、定义:线性表(Linear List)是由同类型的数据元素构成的有序序列的线性结构。
2、顺序表的顺序存储实现:利用数组的 连续储存空间存放 线性表各个元素。
代码:
typedef struct LNode *List;
struct LNode{
ElementType Data[MAXSIZE];
int Last; //线性表的表尾
} ;
定义:List L; 或 struct LNode PtrL;
- 访问下标为i的元素:L.Data[i] 或者 PtrL->Data[ i ];
- 线性表的长度:L.Last+1 或者 PtrL -> Last +1
3、顺序表顺序存储的主要操作的实现
- 初始化(建立空的顺序表)
List MakeEmpty()
{
List L;
L = (List) malloc (sizeof(struct LNode));
L->Last = -1;
return L;
}
- 查找
int Find(ElementType X,List L)
{
int i = 0;
while( L->Data[i] != X && i <= L->Last){
i++;
if(i > L->Last)
return -1;
else return i; //如果没找到就返回-1,找到了就返回储存的位置;
}
}
- 插入(在第i个(1<=i<=n+1) 位置上插入一个值为X的新元素)
void Insert(ElementType X,int i,List L)
{
int j; //首先判断表满不满
if(L->Last == MAXSIZE-1) { //表已经满了,无法插入
printf("表满了”);
return ;
if( i<1 || i>L->Last+2 ){
printf("位置不合法”);
return ;
}
for( j=L->Last ; j >= i-1 ; j-- )
L->Data[j+1] = L->Data[j] ; //将第i到第j个元素倒序向后移动
L->Data[i-1] = X;
L->Last++; //Last仍指向最后一个元素
return ;
- 由于数组空间是连续存放的,所以插入操作的第一步是从第i个元素开始往后挪。(将第i到第j个元素倒序向后移动)第二步才是插入。
- 插入操作的平均移动次数为 n/2 ,平均时间性能为O(n) .
- 删除(删除表中的第i个(1<=i<=n)位置上的元素
void Delete(int i,List L)
{
int j;
if(i<1 || i>L->Last+1){ //+1 是因为数组下标从0开始
printf("不存在第%d个元素,i);
return ;
}
for( j=i;j<=L->Last;j++)
L->Data[j-1] = L->Data[j];
L->Last--;
return ;
- 删除第i个元素,相当于第i个位置空出来了,所以要按照从左往右的顺序往前挪动元素
- 删除操作平均移动次数为(n-1)/2,平均时间性能为O(n).
·
·
·
4、线性表的链式存储实现
示意图:
- 链式存储实现不要求逻辑上相邻的两个元素在物理位置上也相邻,通过“链“建立起数据元素之间的逻辑关系。
- (插入、删除不需要移动数据元素,只需要修改链)
- 缺点:在链表里面,我们只知道链表头,如果想要知道第i个元素在哪里或者是链表的长度是多少,在这两个问题上就比顺序存储要复杂了。
代码:
typedef struct LNode *List;
struct LNode{
ElementType Data;
List Next;
};
struct LNode L;
List L;
5、线性表的链式存储的主要操作的实现
- 求表长
int Length(List L)
{
List p = L; //p指向表的第一个节点
int j = 0; //j是一个计数器
while (p) {
p = p->Next;
j++;
}
return j;
- 用链表遍历的方法去求得表长,所以时间性能为O(n)。
- 查找
(1)按序号查找
List FindKth (int K,List L)
{
List p = L;
int i=1;
while (p!=NULL && i<K ) {
p = p->Next;
i++;
}
if(i==K)
return p; //找到第K个,返回指针
else return NULL;
}
(2)按值查找
List FindX(ElementType X,List L)
{
List p = L;
while(p != NULL && p->Data !=X)
p = p->Next;
return p;
}
平均时间性能为O(n)。
- 插入(在第i-1 (1<=i<=n+1) 个节点后插入一个值为x的新结点
代码:
List Insert(ElementType X,int i,List L)
{
List p,s;
if(i==1) { //新结点插入在表头,申请、填装节点
s =(List)malloc(sizeof(struct LNode));
s->Data = X;
s->Next = L;
return s;
}
p = Findth(i-1,L);
if(p==NULL){
printf("参数i错误");
return NULL;
}else{
s =(List)malloc(sizeof(struct LNode)); //申请、填装节点
s->Data = X;
s->Next = p->Next; //新结点插入在第i-1个节点后面
p->Next = s;
return L;
}
}
- 1、先构造一个新节点,用s指向
- 2、再找到链表的第i-1个节点,用p指向
- 3、然后修改指针,插入节点(先将新结点的Next指向i-1后面的节点,再将第i-1个节点指向新的s节点,防止链表的丢失)
- 平均查找次数为 n/2,平均时间性能为O(n)
示意图:
- 删除
代码实现:
List Delete(int i,List L)
{
List p,s;
if(i==1){
s = L; //若要删除的是第一个节点,s指向第一个节点,从链表中删除
if(L!=NULL) L=L->Next;
else return NULL;
free(s);
return L;
}
p = FindKth(i-1,L);
if(p==NULL){
printf("第%d个节点不存在,i-1");
return NULL;
}else if(p->Next == NULL){
printf("第%d个节点不存在",i);
return NULL;
}else{
s = p->Next;
p->Next = s->Next; //s指向第i个节点,从链表中删除
free(s); //释放被删除节点
return L;
}
}
- 1、先找到链表的第i-1个节点,用p指向
- 2、再用指针s指向要被删除的节点,即p的下一个节点
- 3、然后修改指针,让p指向s的下一个节点,即删除s所指节点
- 4、最后释放s所指节点的空间
示意图:
·
·
·
·
·
附:文中所有PPT图片均来自中国大学mooc 浙江大学《数据结构》课程!!