链表总结(c语言实现)
关于链表的操作主要包括4种
1 单链表
2单向循环
3双向链表
4双向循环
具体操作如下
1 单链表(包括带头结点与不带头结点的,带头结点的在尾删时不需要考虑第一个节点是否存在,尾插不需要考虑是不是有结点存在)
类型定义
typedef struct slnode {//结构体类型
int data;//存放数据
struct slnode* next;//存放下一个位置的指针
}slonde;
slonde* plist=NULL;//头指针
先看不带头结点的(包括尾插,头插,尾删,头删,在第i个节点后插入)
尾插
slnode* creatnode(int x) {//创建一个节点
slnode* newnode = (slnode*)malloc(sizeof(slnode));
newnode->data = x;
newnode->next = NULL;
return newnode;
}
void spushtail(slnode** pphead) {//尾插,需要改变plist指向位置,传地址
int x;//为插入数据值
scanf("%d", &x);
slnode* newnode = creatnode(x);
if (*pphead == NULL) {//如果不讨论后面cur->next会报错
*pphead = newnode;
}
else {
slnode* cur = *pphead;//用尾指针指向下一个结点
while (cur->next) {//注意是cur->next,如果是cur下面cur->next会报错,其实这个循环的作用是方便多次调用每次尾指针都指向最后一个结点
cur = cur->next;
}
cur->next = newnode;
}
}
void sprint(slnode* phead) {//打印链表
while (phead) {
printf("%d->",phead->data);
phead = phead->next;
}
printf("NULL\n");
}
尾删
oid spoptail(slnode** pphead) {//尾删,可能对plist指向发生改变在最后一次删除时指向改为空
if (*pphead == NULL) {
*pphead=NULL;
}
if ((*pphead)->next == NULL) {//需要对第一个结点进行判断,不然后面第一个结点不会被置空
*pphead=NULL;
}
else {//需要一个前指针指向最后一个结点前面,将前面节点的next置空和一个指针判断是不是到达尾部
slnode *pre= *pphead;
slnode *cur= *pphead;
while (cur->next) {
pre = cur;
cur = cur->next;
}
pre->next = NULL;
free(cur);//释放空间
}
}
头插
void spushhead(slnode** pphead){//头插
int x;
scanf("%d", &x);
slnode* newnode = creatnode(x);
newnode->next = *pphead;
*pphead = newnode;
}
头删
void spophead(slnode** pphead) {
if (*pphead == NULL) {
*pphead = NULL;
}
else {//需要一个前指针指向被删除的,后指针指向需要连接的
slnode *pre= *pphead;
slnode *cur= (*pphead)->next;
*pphead = cur;
}
}
在第i个结点后插入
void sinsert(slnode** pphead) {//在某个结点后插入,传值传地址都可以,如果在第一个结点插入就要传递地址
slnode* cur = *pphead;//新结点链接cur
slnode* pre = *pphead;//通过pre链接新结点
int i;
int count = 0;
scanf("%d", &i);//插入位置
while (cur) {
pre = cur;
count++;
cur = cur->next;
if (count == i) {
break;
}
}
int x;
scanf("%d", &x);
slnode* newnode = creatnode(x);
newnode->next = cur;
pre->next = newnode;
}
带头结点的(尾插,尾删)//还有的操作就不列举了,方法类似
尾插
void shpushtail(slnode** pphead) {
slnode* head = creatnode(1);//头结点,注意当多次调用这个函数时需要对是不是要创建头结点进行讨论,需要添加多个节点在此函数加入循环即可
*pphead = head;
slnode* cur = head;
int x;
scanf("%d", &x);
slnode* newnode = creatnode(x);
cur->next = newnode;
}
void shprint(slnode* phead) {
phead = phead->next;//跳过头结点
while (phead) {
printf("%d->", phead->data);
phead = phead->next;
}
printf("NULL\n");
}
尾删
void shpoptail(slnode** pphead) {
slnode* cur = *pphead;
slnode* pre = *pphead;
while (cur->next) {//找尾
pre = cur;
cur = cur->next;
}
pre->next = NULL;
if ((*pphead)->next) {//如果首结点为空,不用free头结点
free(cur);
}
}
2 单向循环链表创建(尾插)带头
slnode* creatrnode(int x, slnode*head) {
slnode* newnode = (slnode*)malloc(sizeof(slnode));
newnode->data = x;
newnode->next = head;
return newnode;
}
void srpushtail(slnode** pphead) {
slnode* head = creatnode(1);//设置头结点next为空
*pphead = head;
slnode* cur = head;//用cur指向新结点
int x;
scanf("%d", &x);
slnode* newnode = creatrnode(x, head);//新结点next指向头结点
cur->next = newnode;
}
void srprint(slnode* phead) {
slnode* cur = phead->next;//让头结点不改变
while (phead !=cur) {
printf("%d->", cur->data);
cur = cur->next;
}
printf("NULL\n");
}
3双向链表(带头)
sdnode* creatdnode(int x,sdnode* cur) {
sdnode* newnode = (sdnode*)malloc(sizeof(sdnode));
newnode->next = NULL;
newnode->data = x;
newnode->pre = cur;
return newnode;
}
void sdprint(sdnode* phead) {
phead = phead->next;
while (phead) {
printf("%d->", phead->data);
phead = phead->next;
}
printf("NULL\n");
}
void sdpush(sdnode** pphead){
sdnode* head=(sdnode*)malloc(sizeof(sdnode));//设置头结点
head->pre = NULL;
head->next = NULL;
head->data = 1;
*pphead = head;
int x;
scanf("%d", &x);
sdnode* cur = head;
sdnode* newnode = creatdnode(x, cur);
cur->next = newnode;
cur = newnode;
}
4双向循环与单向循环类似