目录
尾插
1.创建指针变量tail,让tail=head。
2.tail遍历链表直到为NULL,即找到了尾节点
3.创建一个新节点newnode
4.让tail的next指向newnode完成连接
5.把newnode给给tail,让tail跳到newnode头上。
#include<assert.h>
//定义一个结构体,一个链表中的节点就是一个结构体,每个节点里面都存有data和next,next存放着下个节点的地址
typedef struct node
{
int data;
struct node* next;
}node;
//尾插函数
node* sltpushback(struct node* head)
{
struct node* tail = head;
while(tail->next!=NULL)
{
tail = tail->next;
}
for (int i = 1; i <= 3; i++)
{
struct node* temp = (struct node*)malloc(sizeof(struct node));
if(temp==NULL)//判断是否开辟成功
{
perror("malloc fail");
}
temp->data = i;
temp->next = NULL;
tail->next = temp;
tail = temp;
}
return head;
}
node* sltprint(node* head)
{
head = head->next;
while (head!=NULL)
{
printf("%d->", head->data);
head = head->next;
}
printf("NULL");
return head;
}
int main()
{
struct node* head;
head =(node*)malloc(sizeof(node));
if(head==NULL)//判断是否开辟成功
{
perror("malloc fail");
}
head->next = NULL;
head= sltpushfront(head);
sltprint(head);
return 0;
}
头插
数据结构入门——头插法创建链表_本题目要求以头插法建立单链表。_skchendj的博客-CSDN博客
只需要在尾插的基础上改一下就可以了。
node* SLTpushFront(node* head)
{
node* tail = head;
for (int i = 1; i <= 10; i++)
{
node* tmp = (node*)malloc(sizeof(node));
if(tmp==NULL)//判断是否开辟成功
{
perror("malloc fail");
}
tmp->data = i;
tmp->next = head->next;//用新节点指向原来的头节点
head->next = tmp;//把头指针指向新节点
}
return head;
}
也可以改简洁一点代码,既然尾插要开辟新节点,头插又要开辟新节点,干脆写个开辟新节点的函数,在头插尾插里直接调用就可以了。
void* Creatnode()
{
node* newnode;
for (int i = 1; i <= 10; i++)
{
newnode = (node*)malloc(sizeof(node));
if(newnode==NULL)//判断一下是否开辟成功
{
perror("malloc fail");
}
newnode ->data = i;
newnode->next = NULL;
}
return newnode;
}
node* SLTpushFront(node* head)
{
node* tail = head;
for (int i = 1; i <= 10; i++)
{
node* tmp=Creat();
tmp->next = head->next;//用新节点指向原来的头节点
head->next = tmp;//把头指针指向新节点
}
return head;
}
头删
思路:把head赋值给tail然后head跳到下个节点,然后让tail的next置为空,这样第一个节点就连接不到下个节点了
最后把tailfree一下就把第一个节点free掉了。
代码:
node* SLTPopfront(node* head)
{
assert(head);//断言一下,如果,没有一个节点,那还头删什么。
if(head->next)
{
return NULL;
}
else//如果多个节点正常操作
{
node* tail = head;
head = head->next;
tail->next = NULL;
free(tail);
}
return head;
}
尾删
思路:一个src一个tail,把src放head的位置,tail放src的下一节点。让tail和src同步走,但是tail比src快一个节点,当tail走到NULL走完的时候,src刚好走到第二个节点上。
然后把src的next置为空,这样就把链表与最后一个节点的连接断开了
再把tail free掉。
代码:
node* SLTPopback(node* head)
{
assert(head);//断言一下,如果头节点为空就删不了什么,就报错
if (head->next == NULL)//如果只有头节点, 那怎么删呢,直接返回空,让头节点变为空就把头节点删了
{
return NULL;
}
else //否则就是多节点,正常操作就行
{
node* src = head;
node* tail = src->next;
while (tail->next)
{
tail = tail->next;
src = src->next;
}
src->next = NULL;
tail = NULL;
free(tail);
}
return head;//最后要把链表的头结点返回去,不然找不到链表的头结点
}
查改pops
思路:输入一个要查找的值x,然后把head复制给cur,让cur从头节点位置开始找,如果找到了就把cur返回去。如果没找到就让cur继续往下走,直到走到NULL遍历完为止,还没找到就返回NULL;
node* SLTFind(node* head,int x)
{
node* cur = head;
while(cur)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
again:
return NULL;
}
或者这个:
node* SLTFind(node* head,int x)
{
node* cur = head;
while(cur)
{
if (cur->data == x)
{
goto again;
}
cur = cur->next;
}
again:
return cur;
}
node* re=Find(head,x);
找到这个数后用指针re接收,就可以通过修改re来达到改变查找的数的目的了。
在pops前插入
假如有一串数字
现在我们想在3前面插入一个12
1.re是查找函数的返回值,我们要查找3,re就等于3.
2.然后开辟一个新节点,给新节点复制12.
3. 让tail从头节点的位置开始找re,如果找到re就停止,把tail的next连接newnode,newnode的next连接re,这样就完成了在re面前插入12。
//创建新节点,给新节点初始化+赋值12
void* Creatnode()
{
node* newnode;
for (int i = 11; i <= 12; i++)
{
newnode = (node*)malloc(sizeof(node));
if(newnode==NULL)
{
perror("malloc fail");
}
newnode ->data = i;
newnode->next = NULL;
}
return newnode;
}
node* SLTFrontre(node* head,node* re)
{
assert(head);//因为要靠tail从头节点去遍历到re的位置,如果头节点为NULL就不行了
assert(re);//re也不能为空,不然都查不到re怎么插在re前面。
node* newnode = Creatnode();
node* tail = head;
while (tail->next!=re)//如果tail找不到re就一直往下找
{
tail = tail->next;
}
tail->next = newnode;
newnode->next = re;
return head;
}
但是这个代码实际上是有缺陷的。
假如我们要查找的数在头节点上,用这个代码怎么在头节点前插入呢
比如我们要查10,在10前面插入一个12
我们加一个条件:如果要查的数==头节点,就把新节点头插在头节点前。
if (head == re)
{
newnode=sltpushfront(head);
}
在pops后面插入
思路:把re指向的下一个节点给成newnode所指向
然后再把re指向newnode。
void* SLTBackre( node* re)
{
assert(re);//不需要tail来遍历了,也就不用头节点了,不用断言head了
node* newnode = Creatnode();
newnode->next=re->next;
re->next = newnode;
return newnode;
}
删除pops
思路:
1.如果re在头节点,引用头删函数
2.其他情况,先找到re前面的节点
3.然后把re连接的下一个节点给成re上一个节点所连
4.free(re)
void* SLTPopre(node* head,node* re)
{
assert(head);
assert(re);
if(re == head)
{
re=SLTPopBack(head);
}
else
{
node* prev = head;
while (prev->next != re)
{
prev=prev->next;
}
prev->next=re->next;
free(re);
}
return head;
}
删除最后一个节点
比如我们想把re后面这个节点删了
1.把要删除的这个节点命名为Next,Next=re->next;
2.让Next所指向的下一节点给re(即便下一节点为NULL):re->next=Next->next;
3.free(Next)
void* SLTEraseRe(node* re)
{
node* Next = re->next;
re->next = Next->next;
free(Next);
return re;
}