带头结点的头插法(pta 单链表逆序)

这篇博客介绍了如何使用C语言实现单向链表的头插法,用于链表的反转操作。通过示例代码展示了从12345到54321的反转过程,涉及链表节点的创建、插入和遍历。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

先复习一下有头节点的单向链表头插法

为了方便理解,不将函数单独提出来写。

#include<stdio.h>
#include<stdlib.h>
struct node
{
	int  data;
	struct node *next;
};
int main()
{
	struct node *p,*q,*head;
	int a,n,i;
	head=(struct node *)malloc(sizeof(struct node));//头节点的创建 
	head->next=NULL;
	scanf("%d",&n);
	for(i=0;i<n;i++)
	{
		scanf("%d",&a);
		p=(struct node *)malloc(sizeof(struct node));
		p->data=a;//录入数据 
		p->next=head->next;//让新节点指向原来的第一个节点 
		head->next=p;		  //把新节点连到head后面,作为新的第一个节点 
	}
	q=head->next;
	while(q)
	{
		printf("%d ",q->data);
		q=q->next;
	}
	return 0;
}
typedef struct Node *PtrToNode;
struct Node {
    ElementType Data; /* 存储结点数据 */
    PtrToNode   Next; /* 指向下一个结点的指针 */
};
typedef PtrToNode List; /* 定义单链表类型 */




#include <stdio.h>
#include <stdlib.h>

typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
    ElementType Data;
    PtrToNode   Next;
};
typedef PtrToNode List;

List Read(); /* 细节在此不表 */
void Print( List L ); /* 细节在此不表 */

List Reverse( List L );

int main()
{
    List L1, L2;
    L1 = Read();
    L2 = Reverse(L1);
    Print(L1);
    Print(L2);
    return 0;
}

/* 你的代码将被嵌在这里 */

函数Reverse通过对原链表操作,让本来存放的 1 2 3 4 5

就能变成5 4 3 2 1输出   

List Reverse(List L){
    if(L == NULL) return L;
    List temp = L -> Next;
    L->Next = NULL;//清空原链表
    while(temp){
        List p = temp;
        temp = temp -> Next;
        p -> Next = L;//头插法
        L = p;
    }
    return L;
}

                                      ----与其凋零,不如燃烧。(by 科特·柯本)
 

<think>嗯,用户问的是如何用C++通过不带头节点的头插法创建单链表。首先,我需要回忆一下单链表的基本结构。单链表由节点组成,每个节点包含数据域和指向下一个节点的指针。头插法的特点是将新节点插入到链表的头部,所以每次插入后,新节点成为新的头节点。 用户提到的是不带头节点的情况,这意味着链表的第一个节点就是实际存储数据的节点,而不是一个空节点。这和带头节点的链表不同,后者有一个不存储数据的头节点作为起始点。所以在这种情况下,初始链表是空的,头指针直接指向第一个节点或者为空。 接下来,我需要考虑如何实现头插法。每次插入新节点时,新节点的next指针指向原来的头节点,然后更新头指针指向这个新节点。例如,如果链表原本是1 -> 2 -> 3,插入新节点0,结果应该是0 -> 1 -> 2 -> 3。这时候头指针会指向0。 然后,我需要用C++来实现这个结构。首先定义节点结构体,应该包含数据和指向下一个节点的指针。比如: struct ListNode { int val; ListNode* next; ListNode(int x) : val(x), next(nullptr) {} }; 这里构造函数初始化val和next,确保新节点的next初始化为nullptr。 接下来是头插法的函数。因为不带头节点,所以初始时头指针是nullptr。每次插入时,创建新节点,将其next指向当前头节点,然后头指针更新为新节点。例如: void insertAtHead(ListNode*& head, int val) { ListNode* newNode = new ListNode(val); newNode->next = head; head = newNode; } 这里参数是头指针的引用,因为需要修改头指针本身的位置。如果是普通指针参数,函数内部修改不会影响外部的头指针,所以必须使用引用或者二级指针。 然后考虑创建链表的整体流程。可能需要一个循环来连续插入多个元素,比如从用户输入读取数据,直到某个终止条件。例如: ListNode* createList() { ListNode* head = nullptr; int val; while (cin >> val && val != -1) { // 假设-1为结束标志 insertAtHead(head, val); } return head; } 这里需要注意内存管理,确保最后释放链表,避免内存泄漏。但用户的问题可能不需要这部分,但作为示例可能需要提醒。 另外,需要处理空链表的情况。当链表为空时,插入第一个节点,head会从nullptr变为指向新节点,这时候新节点的next自然为nullptr,正确无误。 现在,需要检查是否有错误。比如,头指针是否正确更新,新节点的next是否正确指向原头节点。比如,在示例代码中,insertAtHead函数是否正确处理了这些情况。 可能还需要测试代码,比如打印链表,以验证是否正确插入。例如: void printList(ListNode* head) { while (head) { cout << head->val << " "; head = head->next; } cout << endl; } 测试的时候,创建链表后打印应该显示逆序输入的顺序,因为头插法逆序的。 然后,用户的问题中引用了三个参考资料,但都是关于带头节点的头插法。用户现在问的是不带头节点的情况,所以需要指出两者的区别。例如,在带头节点的情况下,头节点一直存在,插入时不需要改变头节点的位置,只需修改其next指针。而不带头节点的情况下,每次插入都可能改变头指针的位置。 可能还需要注意,在C++中,使用引用传递头指针更方便,避免了二级指针的复杂性。但如果不使用引用,可能需要使用指针的指针,比如ListNode** head,但这样代码会更复杂一些。 最后,总结步骤:定义节点结构,头插函数更新头指针,创建链表的循环插入,以及注意内存管理和输入处理。同时,给出完整的示例代码,帮助用户理解。</think>### C++不带头节点的头插法实现单链表 #### 数据结构定义 ```cpp struct ListNode { int val; // 数据域 ListNode* next; // 指针域 ListNode(int x) : val(x), next(nullptr) {} // 构造函数初始化 }; ``` #### 头插法核心逻辑 ```cpp void insertAtHead(ListNode*& head, int val) { // 使用引用修改头指针 ListNode* newNode = new ListNode(val); // 创建新节点 newNode->next = head; // 新节点指向原头节点 head = newNode; // 更新头指针 } ``` #### 完整创建流程 ```cpp ListNode* createList() { ListNode* head = nullptr; // 初始空链表 int val; while (cin >> val && val != -1) { // 输入-1终止 insertAtHead(head, val); } return head; } ``` #### 关键点说明 1. **头指针更新**:每次插入新节点时,原头节点成为新节点的后继,头指针指向新节点[^3] 2. **时间复杂度**:每次插入操作时间复杂度为$O(1)$ 3. **输入顺序与存储顺序**:输入序列$1 \rightarrow 2 \rightarrow 3$将存储为$3 \rightarrow 2 \rightarrow 1$ #### 内存释放示例 ```cpp void deleteList(ListNode* head) { while (head) { ListNode* temp = head; head = head->next; delete temp; } } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值