数据结构-单向循环链表(初始化、插入结点,头插,尾插,任意插入、删除结点等操作)

数据结构-单向循环链表(初始化、插入结点、删除结点等操作)

单向循环链表

如果把单链表的最后一个节点的指针指向链表头部,而不是指向NULL,那么就构成了一个单向循环链表,通俗讲就是把尾节点的下一跳指向头结点。

  • 我这个代码头节点即为首节点
  • 通过判断当前结点的next结点是否与head结点相等,即可判断是否对单向循环链表遍历完成;
#include <stdio.h>
#include <stdlib.h>

/ 表示是一个节点
typedef struct Node
{
	int data;			// 代表节点中的数据		
	struct Node* pnext; // 代表下一个节点的起始地址
	
}NODE;

//创建一个节点
NODE* creatlist(int num)
{
	NODE* pnode= (NODE*)malloc(sizeof(NODE));
	if(pnode != NULL)
	{
		pnode->data=num;
		pnode->pnext=NULL;
	}
	return pnode;
	
}
//查找尾节点
NODE* findTail(NODE* phead)
{
	if(phead==NULL)
	{
		return NULL;
	}
	//NODE* p=(NODE*)malloc(sizeof(NODE));
	//p = phead;
	NODE* p1=phead;
	while(p1->pnext!=phead)
	{
		p1=p1->pnext;
	}
	return p1;
	
	
}

//头插法
NODE* insertHead(NODE* phead,int num)
{
	NODE* pnew=creatlist(num);
	NODE* ptail=findTail(phead);//查找尾节点,
							//用于将尾节点的pnext指向新的头结点
	if(pnew == NULL)
	{
		return phead;
	}
	if(phead == NULL)
	{
		pnew->pnext=pnew;		自己指向自己
		phead=pnew;				头指针指向新节点
	}
	else
	{
		ptail->pnext=pnew;		将尾节点的pnext指向新的头结点
		pnew->pnext=phead;		链接新节点和头节点
		phead= pnew;			头指针指向新节点
		
	}
	
	return phead;
}

//尾插法
NODE* insertTail(NODE* phead,int num)
{
	NODE* pnew = creatlist(num);
	NODE* ptail = findTail(phead);
	if(pnew == NULL)
	{
		return phead;
	}
	if(ptail == NULL)
	{
		pnew->pnext=pnew;
		phead=pnew;
	}
	else
	{
		ptail->pnext=pnew;		//尾节点的pnext指向新节点
		pnew->pnext=phead;		//新节点的pnext指向头节点
	}
	return phead;
	
}
//计链表节点数
int countNode(NODE* phead)
{
	int n=0;
	if(phead == NULL)
	{
		return 0;
	}
	NODE* p1=phead;
	do
	{
		n =n+1;
		p1=p1->pnext;		p1代替头节点偏移,偏移多少次,计数多少次
	}while(phead!=p1);
	
	return n;	
}
//获取对应节点之前的节点
NODE* getNode(NODE* phead,int npos)
{
	NODE* p = phead;
	if(p== NULL)
	{
		return NULL;
	}
	for(int i=0;i<npos-1;i++)		//对应节点之前的节点,所以为npos-1
	{
		p= p->pnext;				//此时p指向偏移i次以后的节点
	}
	return p;
}
//任意插法
NODE* insertNode(NODE* phead,int npos,int num)
{
	int l = countNode(phead);
	if(npos<0  || npos>l)
	{
		printf("insert pos %d is valid!\n",npos);
		return phead;
	}
	else if(npos==0)	//插入位从0位开始数,所以头插法应为npos=0
	{
		phead = insertHead(phead,num);
	}
	else if(npos==l)
	{
		phead = insertTail(phead,num);
	}
	else if(npos>0 && npos<l) 
	{
		NODE* pnew = creatlist(num);
		if(pnew == NULL)
		{
			return phead;
		}
		if(phead == NULL)
		{
			pnew->pnext=pnew;		//空链表时,新节点的pnext指向自己
			phead=pnew;				//头指针指向pnew
			return phead;
		}
		NODE* p=getNode(phead,npos);	//获取对应节点之前的节点
		NODE* pa=p->pnext;			//原节点待插入位置的pnext节点
	
		p->pnext=pnew;					
		pnew->pnext=pa;
	}
	return phead;
	
}

//删除头结点
NODE* deleteHead(NODE* phead)
{
	NODE* p1=phead->pnext;
	if (phead == NULL)
	{
		return NULL;
	}
	NODE* ptail=findTail(phead); ///查找尾节点的函数一定要放在phead上
	phead=p1;
	
	ptail->pnext=phead;
	return phead;
}

//删除尾节点
NODE* deleteTail(NODE* phead)
{
	
	int npos=countNode(phead);
	NODE* pa=getNode(phead,npos-1);
	NODE* ptail=findTail(phead);
	pa->pnext=phead;
	free(ptail);
	return phead;
}

//删除任意节点
NODE* deleteNode(NODE* phead,int npos)
{
	int len=countNode(phead);
	if(npos<0 || npos>len)
	{
		printf("删除失败,位置不存在\n");
	}  
	else if(npos==0)	//删除位从0位开始数,所以删除头结点应为npos=0
	{
		phead = deleteHead(phead);
		
	}
	else if(npos==len)
	{
		phead = deleteTail(phead);
		
	}
	else 
	{
		NODE* pa=getNode(phead,npos);  ///a,b,c
		NODE* pb=pa->pnext;
		pa->pnext=pb->pnext;
		free(pb);		/释放堆内存
		
		
	}
	return phead;
}
打印当前链表
void display(NODE* phead)
{
	if(phead == NULL)
	{
		printf("list is NULL.\n");
	}
	NODE* p1=phead;
	do 
	{
		printf("%d   ",p1->data);
		p1 = p1->pnext;
	}while(phead!=p1);
	printf("\n");
}
int main(int argc,char *argv[])
{
	NODE* phead = (NODE*)malloc(sizeof(NODE));
	phead = creatlist(2);
	phead->pnext=phead;
	display(phead);
	
	printf("头插法后输出:\n");
	phead = insertHead(phead,1);
	display(phead);
	
	printf("尾插法后输出:\n");
	phead = insertTail(phead,3);
	display(phead);	
	
	printf("任意插法后输出:\n");
	phead = insertNode(phead,2,4);
	phead = insertNode(phead,1,8);
	display(phead);
	/*/
	printf("删除头节点后输出:\n");
	phead = deleteHead(phead);
	display(phead);
	
	printf("删除尾节点后输出:\n");
	phead = deleteTail(phead);
	display(phead);
	/*/
	printf("删除任意节点后输出:\n");
	phead = deleteNode(phead,4);
	//phead = deleteNode(phead,3);  删除位从0位开始数
	display(phead);
	return 0;
}



  • 2
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值