不带头结点的单链表插入方法(头插法与尾插法)
在C++中,单链表是一种常见的数据结构,在动态数据管理方面有着广泛的应用。本文将介绍不带头结点的单链表实现,并采用头插法和尾插法进行插入操作,最后输出链表中的元素。
1. 链表结构体定义
首先,我们定义一个LNode
结构体来表示单链表的结点:
typedef struct LNode{
int data; // 数据域
struct LNode *next; // 指针域,指向下一个结点
}LNode, *LinKL;
在本示例中,链表不带头结点,即L
直接指向首个数据结点。
2. 初始化链表
在使用链表前,我们需要进行初始化:
void init(LinKL &L) {
L = NULL; // 让链表指针为空,表示链表为空
}
此函数将链表指针L
置空,确保其处于可用状态。
3. 头插法实现
头插法的特点是每次插入新结点时,让其成为新的头结点,即新数据的插入顺序与输入顺序相反。
代码实现:
bool InsertL(LinKL &L, int &e) {
while (e != 9999) { // 9999 代表输入结束
LNode *p = (LNode*)malloc(sizeof(LNode));
if (!p) return false; // 内存分配失败
p->data = e;
p->next = L; // 让新结点指向当前的头结点
L = p; // 更新头指针
scanf("%d", &e); // 读取下一个元素
}
return true;
}
代码解析:
- 申请一个新结点
p
,存储当前输入值。 - 让
p->next
指向当前链表头L
,然后L
更新为p
,使p
成为新的头结点。 - 读取下一个数据,继续插入,直到遇到
9999
结束。
4. 尾插法实现
尾插法的特点是每次插入新结点时,让其成为链表的尾部结点,因此新数据的插入顺序与输入顺序相同。
代码实现:
bool InsertTail(LinKL &L, int &r) {
LNode *p = NULL; // 尾指针,初始为空
while (r != 9999) {
LNode *s = (LNode*)malloc(sizeof(LNode));
if (!s) return false; // 内存分配失败
s->data = r;
s->next = NULL; // 新结点的 next 置空
if (L == NULL) {
L = s; // 如果链表为空,新结点直接作为头结点
} else {
p->next = s; // 否则,当前尾结点指向新结点
}
p = s; // 更新尾指针
scanf("%d", &r); // 读取下一个元素
}
return true;
}
代码解析:
- 使用
p
作为尾指针,指向当前链表的最后一个结点。 - 如果链表为空,则让
L = s
,表示s
是首个结点。 - 否则,将
p->next
设为s
,然后p
指向s
,即s
成为新的尾结点。 - 依次读取数据,直到遇到
9999
结束。
5. 输出链表
由于OJ判题对空格敏感,必须按照指定格式输出:
void PrintList(LinKL L) {
while (L) {
printf("%d", L->data);
L = L->next;
if (L) printf(" "); // 仅在下一个结点存在时打印空格
}
printf("\n");
}
代码解析:
- 遍历链表,每次打印当前结点的数据
L->data
。 - 如果
L->next
存在,则打印一个空格,确保格式正确。
6. 主函数实现
int main() {
LinKL L;
init(L); // 初始化头插法链表
int e;
scanf("%d", &e);
InsertL(L, e); // 头插法插入数据
PrintList(L); // 输出头插法结果
LinKL L2;
init(L2); // 初始化尾插法链表
int r;
scanf("%d", &r);
InsertTail(L2, r); // 尾插法插入数据
PrintList(L2); // 输出尾插法结果
return 0;
}
代码解析:
- 初始化两个链表
L
和L2
,分别用于头插法和尾插法。 - 读取数据并插入到链表中。
- 使用
PrintList()
进行格式化输出。
7. 代码运行示例
输入:
3 4 5 6 7 9999
输出:
7 6 5 4 3 // 头插法的结果(倒序)
3 4 5 6 7 // 尾插法的结果(顺序)
结果分析:
- 头插法的结果是输入顺序的逆序。
- 尾插法的结果与输入顺序一致。
8. 总结
//输入3 4 5 6 7 9999一串整数,9999代表结束,通过头插法新建链表,并输出,通过尾插法新建链表,并输出。
//
//注意输出要采用如下代码(因为OJ判题对空格敏感,因此需要用下面的打印代码来做)
打印链表中每个结点的值
//void PrintList(LinkList L)
//{
// L=L->next;
// while(L!=NULL)
// {
// printf("%d",L->data);//打印当前结点数据
// L=L->next;//指向下一个结点
// if(L!=NULL)
// {
// printf(" ");
// }
// }
// printf("\n");
//}
//使用头插法 实现链表的插入操作 不带头结点 L直接指向数据结点
#include <iostream>
#include<stdio.h>
//定义链表结构体
typedef struct LNode{
int data;
struct LNode *next;
}LNode ,*LinKL;
//初始化 不带头结点
void init(LinKL &L){
L =NULL;
}
//头插入
bool InsertL(LinKL &L,int &e){
while(e!=9999){ //一直读入数据,直到9999
LNode * p= (LNode*) malloc(sizeof(LNode));
if(!p){ //分配失败
return false;
}
p->data = e;
p->next =L; //指向L原来指的地方
L = p; //在将L 指向p
scanf("%d",&e);
}
return true;
}
//多定义一个尾指针 p
bool InsertTail(LinKL &L, int &r){
while(r!=9999){
LNode *s,*p = NULL; //tail
s =(LNode*) malloc(sizeof(LNode));
if(!s) return false;
//插入数据
s->data = r;
s->next = NULL;
//s 指向L
if(L==NULL){
L = s;
}
p->next =s;
p = s;
scanf("%d",&r);
}
return true;
}
bool Print1(LinKL L ){
while (L) {
printf("%d", L->data);
L = L->next;
if (L) printf(" "); // 仅在下一个节点存在时打印空格
}
printf("\n");
return true;
}
// void Print(LinKL L){
// LNode *p =L;
// while(p){
// printf("%d->",p->data);
// p =p->next;
//
// }
// printf("NULL");
// }
int main() {i
LinKL L;
//初始化
init(L);
//插入头
int e ;
scanf("%d",&e);
InsertL(L,e);
Print1( L);
// PrintList(L);
//尾插
LinKL L2;
init(L2);
int r;
scanf("%d",&r);
InsertTail(L2,r);
Print1(L2);
return 0;
}
本文介绍了不带头结点的单链表插入方法,包括:
- 头插法(逆序插入)
- 尾插法(顺序插入)
- 链表输出(保证OJ格式)
自己实践的完整代码 有错误请指正。
掌握这两种插入方法,对于理解单链表的基本操作至关重要。希望本文能帮助新手更好地学习C++链表的实现! 🚀