循环链表的建立(尾指针)

本文介绍了一种利用尾指针优化循环链表的操作方法,包括链表的创建、遍历、合并及销毁等基本操作。通过对比头指针,展示了尾指针在提高查找效率上的优势。

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

一、基本思路

1.如果要遍历到最后一个元素,使用头指针的时间复杂度是O(n),若使用尾指针,查找最后一个和第一个的时间复杂度都是O(1);

2.利用函数返回尾指针,通过传递尾指针来完成函数操作;

二、代码如下:


/*
          项目名称:循环链表的建立与基本操作

		  编译环境:VC++ 2008
		  
		  作者相关:。。。
		  
		  最后修改:2019.6.3


          学习目标:1.掌握循环链表的基本操作
		   
		            2.利用尾指针实现的循环链表

          注意事项:1.测试所有功能是否正常

		            2.判断返回的指针值是否有效合法,要看指针所指对象的存储位置在哪,不是看指针是否为局部变量

                    3.使用随机数创建链表时,如果没有延时或延时太短,则建立的链表相同


*/

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

#define OK    1
#define ERROR 0
#define TRUE  1
#define FALSE 0

typedef int   ElemType;
typedef bool  Status;



//定义链表结点结构体
typedef struct Node
{
    ElemType data;
	struct Node *next;

}Node,*LinkList;


//函数声明
Status     ListEmpty( LinkList L );

LinkList   CreateListTail( LinkList *L, int n );//返回尾指针

Status     Match_List(LinkList rear1,LinkList rear2);

Status     OutList_Tail(LinkList rear);//输出尾指针建立的链表

Status     DestroyList( LinkList *L );


int main()
{
    LinkList L1,L2;
   
    LinkList rear1 = CreateListTail(&L1,10);

	printf("使用尾指针建立的循环链表L1为: ");
	OutList_Tail(rear1);

	for(int i=0;i<200000000;i++)//这个地方如果不延时,两个链表的数据会相同
	{
	
	}
	LinkList rear2 = CreateListTail(&L2,10);
  
	printf("使用尾指针建立的循环链表L2为: ");
	OutList_Tail(rear2);

	Match_List(rear1,rear2);
	printf("将L1、L2合并,以L2为头指针,rear1为尾指针得到循环链表为:\n\n");
    OutList_Tail(rear1);

	printf("\n");

    if(DestroyList(&L2))
	{
	    printf("循环链表已被销毁\n\n");
	}
	return 0;
}

Status DestroyList( LinkList *L )
{
    LinkList p,q;

	p = (*L)->next;//p指向第一个结点
    while(p!=*L)
	{
	    q = p->next;
		free(p);//释放p所指向结点的内存
		p = q;//p再指向下一个结点
	}

	free(*L);

	return OK;
}

Status ListEmpty( LinkList L )
{
    if(L->next != L)
		return FALSE;
    else
		return TRUE;
}

//随机产生n个数,利用尾插法完成链表的''整表创建''
LinkList CreateListTail( LinkList *L, int n )
{
	*L = (LinkList)malloc(sizeof(Node));
   
	LinkList rear = *L,s;
	
	srand(time(0));

	for(int i=0;i<n;i++)
	{
	    s = (LinkList)malloc(sizeof(Node));
		s->data = rand()%100+1;
		rear->next = s;
		rear = s;//更新rear的位置到尾结点
	}
	rear->next = *L;

	return rear;
}
//把L2接到L1上
Status     Match_List(LinkList rear1,LinkList rear2)
{
	if(!ListEmpty(rear1->next)&&!ListEmpty(rear2->next))
	{
		LinkList p  = rear1->next;
		rear1->next = rear2->next;
		rear2->next = p->next;

		free(p);
		return OK;
	}
	else

	    return ERROR;
}

Status   OutList_Tail(LinkList rear)
{
	LinkList p= rear->next->next;

	while(p != rear->next)
	{
		printf("%d ",p->data);
		p = p->next;
	}
	printf("\n\n");

	return OK;
}

三、效果

 

### 带有尾指针循环链表实现 #### 定义带尾指针的单向循环链表数据结构 为了提高访问效率,在定义单向循环链表时可以引入尾指针。这样不仅能够快速定位到链表末端,还能简化某些操作逻辑。 ```c typedef struct Node { int data; struct Node* next; } Node; typedef struct { Node *tail; // 尾部指针指向最后一个节点 size_t size; // 记录链表中实际存在的结点数量 } TailCircularLinkedList; ``` 此设计使得每次插入新元素后只需更新`tail->next`即可完成链接关系建立,并保持整个链条形成闭合环状结构[^3]。 #### 创建新的带尾指针的单向循环链表实例 初始化函数负责分配内存并设置初始状态: ```c TailCircularLinkedList* create_tail_circular_linked_list() { TailCircularLinkedList* list = (TailCircularLinkedList*)malloc(sizeof(TailCircularLinkedList)); if (!list) return NULL; list->size = 0; list->tail = NULL; return list; } ``` 当列表为空时,`tail`应设为`NULL`; 非空情况下则始终指向最末位节点。 #### 插入元素至带尾指针的单向循环链表 新增加的方法用于在指定位置之前或之后添加数据项。这里展示如何高效地追加元素到链表结尾处: ```c bool append_to_tail_circular_linked_list(TailCircularLinkedList* list, int value) { if (!list) return false; Node* newNode = (Node*)malloc(sizeof(Node)); if (!newNode) return false; newNode->data = value; newNode->next = NULL; if (list->size == 0) { newNode->next = newNode; // 自身构成闭环 list->tail = newNode; } else { newNode->next = list->tail->next; list->tail->next = newNode; list->tail = newNode; } ++(list->size); return true; } ``` 通过上述方法可以在O(1)时间内完成元素附加动作而无需遍历整条链路来寻找合适的位置。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值