非循环双链表创建打印头插法和尾插法

这篇博客介绍了如何在C语言环境下使用非循环双链表,分别展示了头插法和尾插法的效果。通过实例演示了这两种插入方法在双链表操作中的应用。

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

编译环境vs2015

//头插法

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

typedef struct listinfo *NODE;
typedef struct listinfo node;
typedef struct listinfo
{
	int data;
	node *pnext;
	node *piror;
};

/*初始化链表*/
NODE listInit(NODE phead)
{
	phead = (NODE)malloc(sizeof(node));
	phead->data = 0;
	phead->piror = NULL;
	phead->pnext = NULL;
	return phead;
}

//创建双链表并添加数据,后续节点为NULL,所以只需要处理前驱节点,将新节点和前驱节点连接起来就可以了。
NODE insertlist(NODE phead)
{
	int i, insernum, idata;
	NODE pnew,pend;
	pend = phead->pnext;
	printf("双链表创建节点数据\n");
	printf("录入节点数:");
	scanf("%d", &insernum);
	for (i = 0; i < insernum; i++)
	{
		printf("数据:");
		scanf("%d", &idata);
		pnew = (NODE)malloc(sizeof(node));
		
		pnew->data = idata;
		pnew->pnext = NULL;
		pnew->piror = phead->pnext;//1.先把数据插入首节点
		
		if (phead->pnext != NULL)//后继节点不为NULL时,新节点和后续节点接上
		{
			pnew->pnext = pend->pnext;//2.
			pend->pnext->piror = pnew;//3.
			pend = pnew;//链接节点
		}
		
		phead->pnext = pnew;//4.首节点接上
		pnew->piror = phead;//5.新节点前驱节点接上首节点
		pend = phead;//链接节点
	}
	return  phead;
}
/*打印链表*/
void nodeprit(NODE phead)
{
	NODE temp;
	temp = phead->pnext;
	/*顺序遍历*/
	printf("后继节点遍历\n");
	while (temp != NULL)
	{
		printf("%d ", temp->data);
		if (temp->pnext == NULL)
		{
			break;
		}
		temp = temp->pnext;
	}
	/*前驱节点遍历*/
	printf("\n前驱节点遍历\n");
	
<think>嗯,用户的问题是关于如何用C语言通过结构体封装头尾指针来实现循环双链表的打印。首先,我需要回忆一下循环双链表的基本结构。循环双链表的每个节点应该有一个数据域,前驱指针后继指针,分别指向前一个节点后一个节点。然后,链表结构体需要包含头尾指针,可能还有记录长度的变量。 根据用户提供的引用内容,引用[1]提到了双向链表的结构体描述,包括节点结构体链表结构体。节点结构体有data、fronttail(应该是next?可能用户写错了)指针。而链表结构体可能包含头节点尾节点。引用[2]展示了不带头结点的单向链表的打印函数,不过用户需要的是循环双向链表的打印,所以需要调整指针的遍历方式。 首先,我需要确定循环双链表的节点结构体。通常,节点结构体包含数据域、前驱指针后继指针。例如: typedef struct Node { int data; struct Node* prev; struct Node* next; } Node; 然后,链表的结构体应该包含头指针、尾指针,可能还有大小。例如: typedef struct { Node* head; Node* tail; int size; } CircularDoubleList; 接下来,初始化链表的时候,头尾指针应该指向NULL,或者彼此指向对方,形成循环。不过在创建节点时,如果是空链表入第一个节点时,它的prevnext都指向自己,形成循环。 打印函数需要遍历链表循环双链表的遍历可以从头节点开始,一直往后直到回到头节点为止。但是需要注意处理空链表的情况,即头指针为NULL时直接返回。否则,使用一个do-while循环,从head开始,打印每个节点的数据,然后移动到next,直到回到head。 然后需要考虑如何构造示例代码。用户可能需要完整的代码示例,包括结构体定义、初始化函数、入函数(比如尾插法)、打印函数释放内存的函数。例如,入函数在尾时,如果是空链表,新节点的prevnext都指向自己,并且链表的headtail都指向该节点。如果空,则调整tail的next为新节点,新节点的prev为原tail,新节点的next为head,原head的prev为新节点,然后更新链表的tail为新节点。 在打印函数中,需要处理空链表的情况,输出NULL或者提示链表为空。否则,使用循环遍历,从head开始,直到再次遇到head时停止。使用do-while结构可以确保至少执行一次循环体,适合循环链表的情况。 最后,测试代码部分需要创建链表入几个节点,打印链表,然后释放内存。同时,要注意内存泄漏的问题,确保每个malloc都有对应的free。 可能用户还希望代码中有注释,解释每一步的作用,以及结构体的封装方式。例如,链表结构体封装了headtail,使得操作更便捷。此外,打印函数需要正确处理循环的结束条件,避免无限循环。 总结下来,步骤应该是: 1. 定义节点结构体链表结构体。 2. 初始化链表。 3. 实现入节点的函数(如尾插法)。 4. 实现打印函数,遍历链表并输出每个节点的数据。 5. 编写测试代码,包括入元素、打印、释放内存。 需要注意的细节包括循环链表的指针调整,确保每个节点的prevnext正确指向,以及在打印时正确处理空链表循环终止条件。</think>### C语言实现循环双链表打印示例 #### 1. 结构体定义 ```c #include <stdio.h> #include <stdlib.h> // 节点结构体 typedef struct Node { int data; struct Node* prev; struct Node* next; } Node; // 封装头尾指针的循环双链表结构体 typedef struct { Node* head; Node* tail; int size; } CircularDoubleList; ``` #### 2. 链表初始化 ```c void initList(CircularDoubleList* list) { list->head = NULL; list->tail = NULL; list->size = 0; } ``` #### 3. 尾部入节点 ```c void insertTail(CircularDoubleList* list, int value) { Node* newNode = (Node*)malloc(sizeof(Node)); newNode->data = value; if (list->size == 0) { newNode->prev = newNode; newNode->next = newNode; list->head = newNode; list->tail = newNode; } else { newNode->prev = list->tail; newNode->next = list->head; // 循环指向头节点 list->tail->next = newNode; list->head->prev = newNode; // 更新头节点的前驱 list->tail = newNode; } list->size++; } ``` #### 4. 打印链表核心逻辑 ```c void printList(CircularDoubleList* list) { if (list->size == 0) { printf("NULL\n"); return; } Node* current = list->head; do { printf("%d <-> ", current->data); current = current->next; } while (current != list->head); // 循环终止条件 printf("[HEAD]\n"); } ``` #### 5. 完整测试代码 ```c int main() { CircularDoubleList list; initList(&list); insertTail(&list, 10); insertTail(&list, 20); insertTail(&list, 30); printList(&list); // 输出: 10 <-> 20 <-> 30 <-> [HEAD] // 释放内存(略) return 0; } ``` #### 实现要点 1. **循环特性**:尾节点的`next`指向头节点,头节点的`prev`指向尾节点[^1] 2. **边界处理**:入第一个节点时形成自环,打印时通过`do-while`确保至少执行一次循环 3. **结构封装**:通过`CircularDoubleList`结构体统一管理头尾指针长度[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值