一、按位插入(带头结点)ListInsert(&l,i,e)
- Tips:(此时是 i=1 的情况,插在表头,不执行while循环 )
//在第i个位置插入元素 e (带头结点)
typedef struct LNode{ //单链表结构定义
ElemType data; //存放数据域
struct LNode *next; //指针域
}LNode,*LinkList;
{
/* data */
};
bool ListInsert(LinkList &L,int i,Elemtype e){
if(i<1) // 输入的i必须是合法的
return false;
LNode *p; //指针p指向当前扫描到的结点
int j=0; //当前指针p指向的是第几个结点
p=L; //L指向头结点,头结点是第0个结点(不存储数据)
while(p!=NULL && j<i-1) { //循环找到第i-1个结点
p=p->next;
j++;
}
if(p==NULL) //i值不合法
return false;
LNode *s=(LNode *)malloc(sizeof(LNode)); //申请一个结点空间
s->data=e; //将参数e存储在新申请的结点里面
s->next=p->next; //将s结点指向下一个结点的指针,指向p结点指向下一个结点的指针
p->next=s; // 将p结点指向下一个结点的指针指向s结点,即将结点连接到p之后
return true; //插入成功
}
- Tips:(当 i =3 时,是插入表中,while循环执行两次,与第一种情况基本类似,p指针往后移动两位 )
- Tips:(当 i =5 时,是插入到表尾的情况,此时循环执行的次数最多,因此事时间复杂度也是最大)
- Tips:(当 i =6 时,i >legth ,此时插入的位置超过了表长,p为NULL,不合法,因此return false)
二、按位插入(不带头结点)ListInsert(&l,i,e)
- 思路:在表L中的第i个位置上插入指定元素e,先找到第i-1个结点,将新结点插入其后,但是由于没有头结点,因此i=1时需要特殊处理。
//在第i个位置插入元素 e (不带头结点)
typedef struct LNode{ //单链表结构定义
ElemType data; //存放数据域
struct LNode *next; //指针域
}LNode,*LinkList;
bool ListInsert(LinkList &L,int i,Elemtype e){
if(i<1) // 输入的i必须是合法的
return false;
if(i==1){ //插入第1个结点的操作与其他结点操作不同
LNode *s = (LNode*)malloc(sizeof(LNode)); //申请一个新结点
s->data=e; //将e存储在新结点的数据域
s->next=L;
L=s; // 头指针指向新结点
return true;
}
LNode *p; //指针p指向当前扫描到的结点
int j=0; //当前指针p指向的是第几个结点
p=L; //p指向第一个结点
while(p!=NULL && j<i-1) { //循环找到第i-1个结点
p=p->next;
j++;
}
if(p==NULL) //i值不合法
return false;
LNode *s=(LNode *)malloc(sizeof(LNode)); //申请一个结点空间
s->data=e; //将参数e存储在新申请的结点里面
s->next=p->next; //将s结点指向下一个结点的指针,指向p结点指向下一个结点的指针
p->next=s; // 将p结点指向下一个结点的指针指向s结点,即将结点连接到p之后
return true; //插入成功
}
- Tips:(当 i>1 时,代码中间有点变化,其余逻辑和第一个是一样的)
LNode *p; //指针p指向当前扫描到的结点
int j=1; //当前指针p指向的是第1个结点
p=L; //p指向第1个结点(不是头结点)
三、指定结点的后插操作
- 在结点p之后插入元素e
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
bool InsertNexNode (LNode *p,ElemType e){
if(p==NULL)
return false;
LNode *s=(LNode *)malloc(sizeof(LNode));
if (s==NULL)//内存分配失败(某些情况下是有可能的,比如内存不足)
return false;
s->data=e; //用结点s保存数据e
s->next=p->next;
p->next=s; //将结点s连接到p之后
return true;
}
- 如果要实现后插操作,只需要,先循环找到第i-1个结点,然后调用 renturn InsertNextNode (p,e); 这个函数即可。
四、前插操作
-
因为线性表只能往后查询,前面是未知的,所以要考虑如何找到p的前驱结点,但是这种方法很麻烦,时间复杂度较大为 O(n)。
-
另一种方法:
bool InsertPriorNode (LNode *p,ElemType e){
if(p==NULL)
return false;
LNode *s = (LNode *)malloc(sizeof(LNode));
if (s==NULL) //内存分配失败
return false;
s->next=p->next;
p->next=s; //新结点s连接到p之后
s->data=p->data; //将p中的元素复制到s中
p->data=e; //p中的元素覆盖为e
return true;
}
- 第三种方法:
按位序删除(带头结点)
- ListDelete(&L,i,&e): 删除操作,删除表L中第i个位置的元素,并用e返回删除元素的值。(需要找到第 i-1个结点,修改指针并且用free函数释放第i个结点。
typedef struct LNode{ //单链表结构定义
ElemType data; //存放数据域
struct LNode *next; //指针域
}LNode,*LinkList;
bool ListInsert(LinkList &L,int i,Elemtype e){
if(i<1) // 输入的i必须是合法的
return false;
LNode *p; //指针p指向当前扫描到的结点
int j=0; //当前指针p指向的是第几个结点
p=L; //L指向头结点,头结点是第0个结点(不存储数据)
while(p!=NULL && j<i-1) { //循环找到第i-1个结点
p=p->next;
j++;
}
if(p==NULL) //i值不合法
return false;
if(p->next == NULL) //第i-1个结点后已无其他结点
return false;
LNode *q=p->next; //令q指向被删除结点
e = q->data; //用e返回元素的值
p->next=q->next; //将*q结点从链中断开
free(q); //释放结点的存储空间
return true; //删除成功
}
- 删除指定结点:
(p结点如果是最后一个结点,那么会出错,会出现空指针)
(本节注意体会封装的好处)