循环链表

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

typedef struct data
{
	int id;
	char* name;
}data;

typedef struct node
{
	data da;
	struct node* pNext;
}node;

node* g_phead = NULL;
node* g_pend = NULL;
int length = 0;       //链表长度,创建一个结点+1

void PrintList();
void InitHeadNode();
void InitListElement(data* data, int length);
void InsertNode(int pos, data* data);

//初始化头结点(指针)
void InitHeadNode()
{
	g_phead = (node*)malloc(sizeof(node));
	g_phead->pNext = NULL;
	g_pend = g_phead;
}

//指定位置插入元素
void InsertNode( int pos, data* data)
{
	//创建新结点
	node* new_node = (node*)malloc(sizeof(node));
	new_node->da = *data;
	new_node->pNext = NULL;
	node* pTemp = g_phead;
	int i = 0;
	length++;

	//没有结点时,头结点指向创建的新结点,为第一个结点
	if (g_phead->pNext == NULL)
	{
		g_pend->pNext = new_node;
		//g_pend = new_node;
		new_node->pNext = new_node;  //只有一个结点时,自己指向自己,形成循环
	}
	else
	{
		//在相应位置插入结点
		while (i < pos - 1)
		{
			pTemp = pTemp->pNext;
			i++;
		}
		//插入算法,插入头和插入中间是一样的(这个玩意儿有丶牛逼,画画图就知道每次都会指向第一个结点,最后一个节点一定会指向第一个节点,完成了"循环")
		new_node->pNext = pTemp->pNext;  //如果是添加的尾结点的话,这玩意是将尾结点指向第一个结点,如果是普通的第一位置添加或者中间添加的话就是普通的"连"(新结点连到后一个结点)
		pTemp->pNext = new_node;
	}

}

//在指定位置删除元素并返回
data DeleteData(node* head, int pos)
{
	node* pTemp = head->pNext;
	node* pTemp2 = head->pNext;
	node* pTail = head->pNext;
	int i = 0;
	int j = 0;

	if (pos > length)
	{
		printf("超出长度,删除失败\n");
		return;
	}
	if (head->pNext == NULL)
	{
		printf("链表为空,删除失败\n");
		return;
	}
	//如果删除的节点是位置1
	if (pos == 1)
	{
		//头结点指向第一个结点的下一个节点,使其成为新的第一个结点
		g_phead->pNext = pTemp->pNext;
		data back = pTemp->da;          //记下被删除的值,等下返回
		int i = 0;
		//循环找到尾结点
		while (i < length-1)
		{
			pTail = pTail->pNext;
			i++;
		}
		//因为第一个结点变了,所以尾结点要接上新的第一个结点
		pTail->pNext = g_phead->pNext;
		
		free(pTemp);   //释放被删除结点
		length--;      //链表长度-1
		return back;
	}

	//找到要删除的节点
	while (i < pos - 1)
	{
		pTemp = pTemp->pNext;
		i++;
	}
	//找到要删除的节点的前一个结点
	while (j < pos - 2)
	{
		pTemp2 = pTemp2->pNext;
		j++;
	}
	//node* pFree = pTemp;     //申请一个指针指向目标结点,以便释放
	pTemp2->pNext = pTemp->pNext;
	data back = pTemp->da;
	free(pTemp);
	length--;

	return back;
}

void PrintList()
{
	node* pTemp = g_phead->pNext;
	int i = 0;
	if (pTemp == NULL)
	{
		printf("这是个空链表,打印失败\n");
		return;
	}
	//如果条件只写pTemp->pNext != NULL的话,会无限打印,因为是循环链表,所以需要先算出链表长度,然后打印出完整的链表
	while (i < length)
	{
		printf("%d--->%s    ", pTemp->da.id, pTemp->da.name);
		pTemp = pTemp->pNext;
		i++;
	}
	printf("\n");
}

void InitListElement(data* data, int length)
{
	for (int i = 0; i < length; i++)
	{
		InsertNode(i + 1, &data[i]);
	}
}

//根据位置返回对应结点
node* ReturnNode(node* head, int pos)
{
	node* pTemp = head->pNext;
	int i = 0;

	if (pTemp == NULL)
	{
		printf("链表为空,返回结点失败");
		return NULL;
	}
	//找到结点
	while (i < pos - 1)
	{
		pTemp = pTemp->pNext;
		i++;
	}

	return pTemp;
}

//根据结点数据返回对应结点
node* ReturnNodeByElement(node* head, data* back_data)
{
	node* pTemp = head->pNext;
	
	do
	{
		if (back_data->id == pTemp->da.id && strcmp(back_data->name, pTemp->da.name) == 0)
		{
			return pTemp;
		}
		pTemp = pTemp->pNext;
	} while (pTemp != head->pNext);

	printf("未找到该结点");

	return NULL;
}

void RandomNodePrintList(node* head, node* oneNode)
{
	node* pWatch = oneNode;      //pWatch指向传入的结点,从该结点开始遍历

	if(head->pNext == NULL)
	{
		printf("链表长度为空,遍历失败");
		return NULL;
	}
	//至少要移动一次,保证能够遍历,所以用do while,用其他的也行,for和while也行,不再一一赘述
	do    
	{
		printf("%d  %s -->  ", pWatch->da.id, pWatch->da.name);
		pWatch = pWatch->pNext;
	} while (pWatch != oneNode);    

	printf("\n");
}

int main(void)
{
	InitHeadNode();       //初始化空头

	data d1[4] = { {1,"饥荒"},{2,"瘟疫"},{3,"死亡"}, {4,"战争"} };

	InitListElement(d1, sizeof(d1)/sizeof(d1[0]));

	PrintList();

	data* d2 = (data*)malloc(sizeof(data));
	d2->id = 3;
	d2->name = "闪灵";

	InsertNode(5, d2);

	PrintList();

	data a = DeleteData(g_phead, 4);
	PrintList();
	
	node* pback = ReturnNodeByElement(g_phead, &d1[2]);  //接收返回的对应结点
	
	RandomNodePrintList(g_phead, pback);   //以该结点为初始开始遍历

	system("pause");
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值