链表
作为一种数据结构,链表以其方便的增删查改功能,实现了无数经典有用的程序。
在之前的帖子里,我构建链表的方式是建立一个不储存数据的head节点,然后通过一边输入数据一边建立结点的方式构建整个链表。
与之前不同的是,这里建立的是包含数据的头结点head:
下面是代码,包含创建部分,输出部分,删除部分,和插入部分。
struct Node
{
int data;
Node *next;
};
int n = 0; // 结点数
//=============Node_Creat==============//
Node *Node_Creat()
{
Node *head = NULL; // 头指针置NULL
Node *p1,*p2; // 开辟一个Node大小的空间 使p1和p2指向该空间
p1 = p2 = (Node *)malloc(sizeof(Node));
if(p1 == NULL || p2 == NULL)
{
printf("Overflow\n");
exit(1);
}
scanf("%d",&p1 -> data);
while(p1 -> data >= 0)
{
n++;
if(head == NULL)
{
head = p1;
}
else
{
p2 -> next = p1;
}
p2 = p1;
p1 = (Node *)malloc(sizeof(Node));
if(p1 == NULL)
{
printf("Overflow\n");
exit(1);
}
scanf("%d",&p1 -> data);
}
p1 = NULL;
p2 -> next = NULL;
return head;
}
//============Node_Print==============//
void Node_Print(Node *head)
{
Node *p = head;
if(head == NULL) // 链表为空
{
printf("Empty!\n");
return ;
}
else
{
printf("Total: %d Node\n",n);
while(p != NULL)
{
printf("%d ",p -> data);
p = p -> next;
}
printf("\n");
}
}
//==============Node_Delete()===============//
void Node_Delete(Node *head,int num)
{
Node *p1,*p2;
p1 = head;
if(p1 == NULL) // 链表为空
{
printf("Empty\n");
return ;
}
if(num > n) // 结点不存在
{
printf("Not Found!\n");
return ;
}
n--; // 结点数-1
int i;
for(i = 1; i < num; i++)
{
if(p1 -> next == NULL)break;
p2 = p1;
p1 = p1 -> next;
}
if(p1 == head) // 头节点 即第一个
{
head = p1 -> next;
}
else
{
p2 -> next = p1 -> next;
free(p1);
}
Node_Print(head);
}
//============Node_Insert()============//
void Node_Insert(Node* head,int num,int i_data)
{
Node * newNode;
newNode = (Node *)malloc(sizeof(Node));
if(newNode == NULL)
{
printf("Overflow\n");
exit(1);
}
newNode -> data = i_data;
newNode -> next = NULL;
Node *p1,*p2;
p1 = head;
for(int i = 1 ;i < num; i++)
{
p2 = p1;
p1 = p1 -> next;
}
p2 -> next = newNode;
newNode -> next = p1;
n++; // 结点数+1
Node_Print(head);
}
样例:
链表的反转
我这里采用的方法是 改变两个结点间next指针的指向,原结点next指针指向下一个结点,反转后指向前一个结点。
Node* Node_Reverse(Node* head)
{
Node* pNow = head;//当前结点
Node* pPrv = NULL;//当前结点的前一个结点
Node* pReversedHead = NULL;//反转链表头结点
Node* pNext = NULL;//当前结点的下一个结点
while(pNow != NULL)
{
pNext = pNow -> next;
if(pNext == NULL)//如果当前结点的下一个结点为空,那么反转链表的头结点就是当前结点。
pReversedHead = pNow;
pNow -> next = pPrv;//当前结点指向前一个结点
pPrv = pNow;//pPrv和pNow往前移动。
pNow = pNext;//这里要使用前面保存下来的pNext,不能使用pNow->next
}
return pReversedHead;//返回反转链表头指针。
}
大概的一个流程图(反转第一个结点)
注:红色箭头代表pPrev,pNext和pNow的移动,蓝色代表next指针的指向。