听说,今天是公务员考试,ss祝莘莘学子可以凯旋。关关难过,关关过,再坚持坚持,这句话送给我们大家,这是我高中语文老师给我们说的一句话,陪ss过了一关又一关,好了废话不多说。
1.首先了解一下什么是链表:
typedef int innt;//我们把int 类型换个名字,方便以后改变类型使用单链表
typedef struct seqlist
{
innt x;
struct seqlist* next;//建立一个结构体的指针,用来存放下一个一模一样的“车厢”
}list;
4.单链表的功能实现
<1>尾插
为什么单链表不像顺序表那样需要初始化了,因为单链表再需要的时候会要创建空间,我们在实现功能的时候,就申请空间,所以不需要明明确确的初始化。尾插,我们先把这个数存进一个我们申请好的空间,然后用做好的链表的尾巴链接住此时新数据的头,也就是旧尾巴存上新空间的地址
list* chuang(innt x)
{
list* newnode = (list*)malloc(sizeof(list));
newnode->x = x;
newnode->next = NULL;
return newnode;
}
void pushback(list** head,innt x)
{
list* newnode = chuang(x);
if (*head == NULL)
{
*head = newnode;
return;
}
list* ps = *head;
while (ps->next)
{
ps = ps->next;
}
ps->next = newnode;
}
1*.值得一提的时,为什么使用的时list** head,我们要知道,使用函数传参时,形参就是实参的一个临时拷贝,对形参改变完全不会影响实参,我们尾插的时候,要改变尾巴的next的指向从NULL指向的改编成指向一个新的空间地址,我们如果只传一级指针,但是我们要改变这个指针的指向,虽然传了一个指针,但是我们无法改变它自身,所以我们要传二级指针,保证可以改变它的指向和它自身。
2*.在pushback函数中我们可以看到,ss先进行了一下判断,*head是不是为空指针,为什么呢,如果这是第一个数据,我们的头还没有建立,那它就是头节点。
<2>打印
我们实现了尾插数据,当然得看看有没有写成功,可以进行调试,但是为了更加直观和方便,也是进一步学习遍历链表,我们写一下打印的函数,打印不需要改变里面的任何指针的指向,所以我们只需要一级指针就可以,如何遍历单链表呢?
我们的尾结点都和一个头结点相连接(头尾除外),所以我们只需要将头节点变成下一个的头节点,而下一个的头节点不就是我们刚才的尾结点存储的那个地址嘛,所以定义一个指针,指向头部,用它去遍历,不要改变定义好的头结点
void print(list* head)
{
assert(head);
list* ps = head;
while (ps)
{
printf("%d->", ps->x);
ps = ps->next;
}
}
<3>头插,我们要知道,单链表单的意思是,单向的,是一个方向循环的,就是只能从头的方向向尾巴循环遍历,那我们怎么实现头部增加,并且把新数据连在旧数据的前面呢?我们可以创建一个头指针,相对来说他就是不动的,他就做头,我们每次头插新数据时,把新数组的地址当作头,然后再进行链接,思路明了,代码实操。
void pushfront(list** head,innt x)
{
list* ps=chuang(x);
assert(ps);
if ((*head) == NULL)
{
*head = ps;
return;
}
ps->next = *head;
*head = ps;
}
<4>尾巴删除
因为单向循环,所以我们遍历一下,尾巴的标志是什么,就是它的next指针指向的是NULL,所以我们要以它作为条件,进行循环遍历,但是我们还需要尾巴的上一个结点,因为它成了新的尾结点,所以我们有两种思路,第一种就是定义两个指针,两者一前一后,紧挨着进行遍历,最后释放尾结点即可,第二种思路,就是用指针的next->next进行判断为空,值得注意的就是,如果只有一个数据,此时就是尾结点,-next=NULL,不能将NULL再指向next,会报错,所以我们先写一个只有一个数据的时候。思路明了,代码实操。
void popback(sltnode** phead)//第一种
{
assert(phead);
assert(*phead);// 链表不为空
if ((*phead)->next == NULL)
{
free(*phead);
*phead = NULL;
return;
}
sltnode* petail = *phead;
sltnode* prev = NULL;
while (petail->next)
{
prev = petail;
petail = petail->next;
}
prev->next = NULL;
free(petail);
petail = NULL;
}
//第二种
void popback(list** head)
{
assert(*head);
assert(head);
list* ps = *head;
if (ps->next == NULL)
{
free(ps->next);
free(ps);
ps = NULL;
return;
}
while (ps->next->next != NULL)
{
ps = ps->next;
}
free(ps->next);
ps->next = NULL;
}
<5>头删
这个有了以往的经验,我们想象,只需要更改头结点,让新的头结点是刚才的头结点的next指向的那块。
void popfront(list** head)
{
assert(*head);
assert(head);
list* ps = *head;
*head = ps->next;
free(ps);
ps = NULL;
}
<6>在指定的数字前面插入新的数据
首先我们需要找到这个指定的数字,然后在它前面插数据,则需要改变这个数字上个结点的尾结点指向,并使新数据的尾结点指向这个指定的数字。
void insert(list** head, int pos, innt x)
{
if ((*head)->x == pos)
{
pushfront(head,x);
return;
}
list* ps = chuang(x);
list* ret = find(head, pos);
if (ret == NULL)
{
printf("查无此数");
return;
}
ps->next = ret->next;
ret->next = ps;
}
观察代码,其实和刚才头插有些许相同,因为我需要指定数的上一个结点,所以先判断一下他是不是头结点,如果是,则直接头插就行,不是的话,我们用ps->next->x,来找到那个指定数的上一个结点。
<7>在指定的数字后面插入新的数据
这个更好做了,直接找数,把尾结点更改即可。
void insertafter(list** head, int pos, innt x)
{
assert(head);
assert(*head);
list* ret = find(head, pos);
list* ps = chuang(x);
ret->next = ps;
ps->next = NULL;
}
<8>指定数字的删除
void eraser(list** head, int pos)
{
assert(head);
assert(*head);
if ((*head)->x == pos)
{
popfront(head);
return;
}
list* ret = find(head, pos);
list* ps = ret->next;
ret->next = ps->next;
free(ps);
ps = NULL;
}
还是和刚才一样,先判断是不是头结点,不是的话,我们找一下,指定的数的上一个结点,然后更改它的尾结点,再进行释放指定的数的空间即可;
<9>销毁
void destory(list** head)
{
assert(*head);
assert(head);
list* ps = *head;
while (ps)
{
list*ret = ps->next;
free(ps);
ps = ret;
}
*head = NULL;
}
销毁的话,我们就需要两个指针,一个负责被销毁,一个负责遍历链表,所以第二个要在第一个的前面,进行遍历,最后把头结点置为空。
最后我们还是代码分享
//list.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int innt;
typedef struct seqlist
{
innt x;
struct seqlist* next;
}list;
void pushback(list** ps,innt x);
void pushfront(list** ps,innt x);
void print(list* ps);
void popback(list** ps);
void popfront(list** ps);
void insert(list** ps, int pos, innt x);
void insertafter(list** ps, int pos, innt x);
void eraser(list** head, int pos);
void destory(list** head);
//list.c
#include"seqlist.h"
list* chuang(innt x)
{
list* newnode = (list*)malloc(sizeof(list));
newnode->x = x;
newnode->next = NULL;
return newnode;
}
void pushback(list** head,innt x)
{
list* newnode = chuang(x);
if (*head == NULL)
{
*head = newnode;
return;
}
list* ps = *head;
while (ps->next)
{
ps = ps->next;
}
ps->next = newnode;
}
void print(list* head)
{
assert(head);
list* ps = head;
while (ps)
{
printf("%d->", ps->x);
ps = ps->next;
}
printf("\n");
}
void pushfront(list** head,innt x)
{
list* ps=chuang(x);
assert(ps);
if ((*head) == NULL)
{
*head = ps;
return;
}
ps->next = *head;
*head = ps;
}
void popback(list** head)
{
assert(*head);
assert(head);
list* ps = *head;
if (ps->next == NULL)
{
free(ps->next);
free(ps);
ps = NULL;
return;
}
while (ps->next->next != NULL)
{
ps = ps->next;
}
free(ps->next);
ps->next = NULL;
}
void popfront(list** head)
{
assert(*head);
assert(head);
list* ps = *head;
*head = ps->next;
free(ps);
ps = NULL;
}
list* find(list** head, int pos)
{
list* ps = *head;
while (ps)
{
if (ps->next->x == pos)
{
return ps;
}
ps = ps->next;
}
return NULL;
}
void insert(list** head, int pos, innt x)
{
if ((*head)->x == pos)
{
pushfront(head,x);
return;
}
list* ps = chuang(x);
list* ret = find(head, pos);
if (ret == NULL)
{
printf("查无此数");
return;
}
ps->next = ret->next;
ret->next = ps;
}
void insertafter(list** head, int pos, innt x)
{
assert(head);
assert(*head);
list* ret = find(head, pos);
list* ps = chuang(x);
ret->next = ps;
ps->next = NULL;
}
void eraser(list** head, int pos)
{
assert(head);
assert(*head);
if ((*head)->x == pos)
{
popfront(head);
return;
}
list* ret = find(head, pos);
list* ps = ret->next;
ret->next = ps->next;
free(ps);
ps = NULL;
}
void destory(list** head)
{
assert(*head);
assert(head);
list* ps = *head;
while (ps)
{
list*ret = ps->next;
free(ps);
ps = ret;
}
*head = NULL;
}
//test.c
#include"seqlist.h"
void test1()
{
list* ps=NULL;
pushback(&ps,1);
pushback(&ps,2);
pushback(&ps,3);
pushfront(&ps, 100);
eraser(&ps, 1);
print(ps);
}
int main()
{
test1();
return 0;
}
欢迎大佬指出错误,谢谢观看