#include <iostream>
// 2.2 单链表的插入和删除
typedef struct LNode{
int data;
LNode *next;
}LNode,*LinkList;
// 不带头节点
bool init01(LinkList &L){
L = NULL;
return true;
}
// 带头节点
bool init02(LinkList &L){
L = (LNode*)malloc(sizeof(LNode));
if (L == NULL){ // 存储空间不够则返回false
return false;
}
L->next = NULL;
return true;
}
// 1. 带头节点的指定位置后插
// (1) 声明一个指针指向头节点,让其开始循环后移,直到指向第 i 个位置的前一个位置, 可以使用for循环或while循环
// (2) 使用malloc给新节点分配空间,并创建一个指针指向它
// Tip:
// (1) 使用的不再是连续空间,故无法通过指针加某个数的方式到达位置
// (2) 需要再考虑表头插入、表尾插入会发生什么事情:
bool ListInsert01(LinkList &L, int place, int element){
if (place < 1){
return false;
}
LNode *pt = L; // pt指向头节点
// 使用for循环
// for(int i = 0; i < place-1; i++){
// if (pt != NULL){ // 如果插入位置大于节点数+2
// pt = pt->next;
// }
// else{
// return false;
// }
// }
// 使用while循环到达指定位置
// 逻辑一样
int j = 0;
while (j < place-1 && pt!=NULL) {
pt = pt->next;
j++;
}
if(pt == NULL){
return false;
}
LNode *nod = (LNode*)malloc(sizeof(LNode));
nod->data = element;
nod->next = pt->next;
pt->next = nod;
return true;
}
// 2. 不带头节点的指定位置前插
// (1) 声明一个指针指向第一个节点,循环后移,直到找到插入节点的前一个位置, 循环的次数有所变化
// (2) 和之前一样,进行插入操作
// Tip:
// (1) 由于声明的指针指向第一个位置,那么按照一般情况插入位置只能>=2,需要对插入位置为1做特殊处理
bool ListInsert02(LinkList &L, int place, int element){
if (place < 1){
return false;
}
// 需要额外考虑插入位置为1, 如果单链表当前没有元素,插入也是正确的
if (place == 1){
LNode *nod = (LNode*) malloc(sizeof(LNode));
nod->data = element;
nod->next = L;
L = nod;
return true;
}
// 相比没有头节点,循环次数少1,其它一样
LNode *pt = L;
int j = 0;
while (j < place - 2 && pt != NULL){
pt = pt->next;
j++;
}
// 一模一样, 可以定义一个函数复用
if (pt == NULL){
return false;
}
LNode *nod = (LNode*) malloc(sizeof(LNode));
nod->data = element;
nod->next = pt->next;
pt->next = nod;
return true;
}
// 3. 节点前插操作, 有没有头节点操作相同
// (1) 互换节点和插入节点的元素
// (2) 指针重新指一下
// Tip:
// (1) 先交换元素或者是先指针重指都没有关系
// (2) 如果插入的节点为空,那么没有任何意义,在NULL前面插入位置是不合法的
bool insertPriorNode(LNode *node, LNode *insert){
if (node == NULL || insert == NULL){
return false;
}
int temp = node->data;
node->data = insert->data;
insert->data = temp;
insert->next = node->next;
node->next = insert;
return true;
}
// 4. 带头节点单链表按位序删除, 返回删除值
// (1) 循环,找到待删除元素的前一个元素,和1不一样的是,插入可以插入到NULL的位置,而删除不可以
// (2) 让该节点指向下下个节点或NULL
// (3) free掉删除的节点
bool ListDelete01(LinkList &L, int place, int &a){
//
if (place < 1){
return false;
}
LNode *pt = L;
int j = 0;
while (j < place-1 && pt->next!=NULL) { // 待插入的位置可以为NULL,但是待删除的位置不能是NULL
pt = pt->next;
j++;
}
if(pt->next == NULL){
return false;
}
// 指向下下个节点
LNode *q = pt->next;
a = q->data;
pt->next = q->next;
free(q); // free掉删除的节点
return true;
}
// 5. 不带头节点单链表按位序删除, 返回删除值
// (1) 循环,找到待删除元素的前一个元素,和1一样,最多只能循环到指向最后一个元素
// (2) 让该节点指向下下个节点或NULL
// (3) free掉删除的节点
// Tip:
// (1) 需要额外考虑第一个节点的删除操作
bool ListDelete02(LinkList &L, int place, int &a){
if (place < 1){
return false;
}
if (place == 1){
LNode *firstNod = L;
a = firstNod->data;
L = L->next;
free(firstNod);
return true;
}
LNode *pt = L;
int j = 0;
while (j < place - 2 && pt->next != NULL){
pt = pt->next;
j++;
}
if(pt->next == NULL){
return false;
}
// 指向下个节点的方法和 4 一模一样
LNode *nextNode = pt->next;
a = nextNode->data;
pt->next = nextNode->next;
// nextNode->next = NULL;
free(nextNode);
return true;
}
int main() {
LinkList L01;
init02(L01); // 带头节点初始化方法
ListInsert01(L01,1,1);
ListInsert01(L01,2,3);
ListInsert01(L01,3,4);
ListInsert01(L01,2,2); // 1234
LinkList L02;
init01(L02); // 不带头节点初始化方法
ListInsert02(L02,1,1);
ListInsert02(L02,2,3);
ListInsert02(L02,3,4);
ListInsert02(L02,2,2); // 1234
int a; // 带头节点删除
ListDelete01(L01,2,a); // L 134
printf("%d\t",a); // 2
ListDelete01(L01,3,a); // L 13
printf("%d\t",a); // 4
ListDelete01(L01,1,a); // L 4
printf("%d\n",a); // 1
//不带头节点删除
ListDelete02(L02,2,a); // L 134
printf("%d\t",a); // 2
ListDelete02(L02,3,a); // L 13
printf("%d\t",a); // 4
ListDelete02(L02,1,a);
printf("%d\n",a);
}
02 单链表的初始化、插入、删除
于 2023-01-07 19:33:48 首次发布