目录
所有代码均经过测试,附运行截图
实验环境
vscode 2022 社区版
vscode 2022 社区版的搭建:
https://blog.youkuaiyun.com/lijiamingccc/article/details/123552207
1.初始化单链表
带头节点的单链表初始化
bool Init_HeadList(LinkList& L) {
L = (LNode* )malloc(sizeof(LNode));//分配一个头节点
if (!L) return false;
L->next = NULL;
return true;
}
不带头节点的单链表初始化
// 初始化单链表 不带头节点
bool InitList(LinkList &L){
L = NULL;
return true;
}
2.按位查找
j<=i 是定位到第i个,j<i是定位到i-1个
LNode* GetElem(LinkList L,int i){
if (i<=0) return NULL;
int j = 1;
LNode *p = L;
// 当结点P存在,并且j<=i
// 在这里注意区分<=和<的区别
while (p && j<=i){
// 将下一个结点赋值给p
p = p->next;
j++;
}
return p;
}
3.按值查找
LinkList LocateElem(LinkList L,int e){
LNode *p = L;
while (p && p ->data != e){
p = p->next;
}
return p;
}
4.计算单链表长度
int Length(LinkList L){
int len=0;
LNode *p =L;
while (p->next){
len++;
p = p->next;
}
return len;
}
5.插入操作
后插操作
后插操作 在结点p之后插入元素e
bool InsertNextNode(LNode *p,int e){
if(!p) return false;
LNode *s = (LNode *)malloc(sizeof(LNode));
// 内存空间不足,失败
if(!s) return false;
s->data = e;
s->next = p->next;
p->next = s;
return true;
}
前插操作
前插和后插的操作类似,前插是在后插的基础上交换了一下两个节点的数据域
bool InsertPriorNode(LNode *p,int e){
if (!p) return false;
LNode *s = (LNode *)malloc(sizeof(LNode));
if (!s) return false;
// 依然是在p结点之后插入一个结点s
s ->next = p ->next;
p ->next = s;
// 将s和p结点的数据域互换
s ->data = p->data;
p ->data = e;
return true;
}
结合插入和查找
在第i个位置插入元素e
// 便捷调用插入,带头节点的插入操作,在第i个位置插入元素e
bool ListInsert(LinkList& L, int i, int e) {
if (i < 1) return false;
LNode *p = GetElem(L, i-1);
if (!p) return false;
// InsertPriorNode也可以
return InsertNextNode(p, e);
}
6.删除节点
注意为什么要i-1,因为i是位序,而i-1是下标
bool ListDelete(LinkList &L,int i,int &e){
if(i<1) return false;
LNode *p = GetElem(L,i-1);
if(!p || !(p->next)) return false;
LNode *q = p->next;
e = q->data;
p->next = q->next;
free(q);
return true;
}
7.建立链表
头插法建立链表
头插法,带头节点
当L是空表时,L是头节点,插入的第一个数据是在L后面的
开始插入第二个第三个…就是头插的方式
LinkList List_HeadInsert(LinkList &L){
L = (LinkList)malloc(sizeof(LNode));
L ->next = NULL;
LNode *s;
int x;
printf("正在使用头插法插入元素:\n");
while(x!=9999){
scanf("%d",&x);
if(x==9999) break;
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
s->next = L->next;
L->next = s;
}
return L;
}
尾插法建立链表
// 尾插法 带头节点
LinkList List_TailInsert(LinkList &L){
L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;
LNode* s, * r = L; //r表示表尾指针
int x;
printf("正在使用尾插法插入元素:\n");
while(x!=9999){
scanf("%d",&x);
if(x==9999) break;
s = (LNode*)malloc(sizeof(LNode));
s->data = x;
r->next = s; //这一步不可以缺失,处于循环之中,缺失则错
r = s;
}
r ->next = NULL; // 将队尾元素置空
return L;
}
tip:定义一个输出链表的函数
void print(LinkList L) {
LNode* s = L;
while (s->next!=NULL) {
s = s->next;
printf("%d ",s->data);
}
}
主程序测试
int main(){
LinkList L;
Init_HeadList(L);
//List_HeadInsert(L);
//print(L);
List_TailInsert(L);
print(L);
printf("\n链表的第1个元素是%d\n",GetElem(L, 1)->data);
printf("链表的长度是%d\n",Length(L));
int e;
// 删除链表节点
ListDelete(L, 3, e);
printf("删除的第3个元素是%d\n",e);
printf("当前的链表为");
print(L);
// 插入链表节点
printf("\n请输入要插入的元素的值: ");
scanf("%d",&e);
ListInsert(L, 3, e);
printf("删除的第3个元素是%d\n",e);
printf("当前的链表为");
print(L);
return 0;
}