#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;
}
循环链表
最新推荐文章于 2022-03-02 20:12:52 发布