目录
一、双向链表初始化
二、尾插
问题1:什么时候传一级指针,什么时候传二级指针呢?
三、打印
四、尾删
五、头插
六、头删
七、pos之前插入
八、删除pos位置的节点
总代码:
List.h
#pragma once
#include<stdio.h>
#include<stdlib.h>
#include<malloc.h>
#include<assert.h>
typedef int DataType;
typedef struct ListNode
{
DataType data;
struct ListNode* next;
struct ListNode* prev;
}LTNode;
//这次不传二级指针,用返回值
LTNode* InitList();
//尾插
void ListPushBack(LTNode* phead, DataType x);
//尾删
void ListPopBack(LTNode* phead);
//头插
void ListPushFront(LTNode* phead, DataType x);
//头删
void ListPopFront(LTNode* phead);
//查找
LTNode* ListFind(LTNode* phead, DataType x);
//pos位置之前插入
void ListInsert(LTNode* pos, DataType x);
//删除pos位置结点
void ListErase(LTNode* pos);
List.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"
//增加节点
LTNode* BuyNode(DataType x)
{
LTNode* newnode = (LTNode*)malloc(sizeof(LTNode));
if (newnode == NULL)
{
printf("newnode failed\n");
exit(-1);
}
newnode->data = x;
newnode->next = newnode->prev = NULL;
return newnode;
}
//初始化
LTNode* InitList()
{
//带头节点,循环链表
//哨兵位头结点
LTNode* phead = (LTNode*)malloc(sizeof(LTNode));
phead->next = phead->prev = phead;
return phead;
}
//尾插
void ListPushBack(LTNode* phead, DataType x)
{
assert(phead);
//LTNode* newnode = BuyNode(x);
//LTNode* tail = phead->prev;
//tail->next = newnode;
//newnode->prev = tail;
//newnode->next = phead;
//phead->prev = newnode;
//改写:
ListInsert(phead,x);
}
//打印
void ListPrint(LTNode* phead)
{
assert(phead);//如果phead没有初始化,则会为NULL,而带头结点的指针不会为NULL,所以在此断言
LTNode* cur = phead->next;
while (cur != phead)
{
printf("%d->",cur->data);
cur = cur->next;
}
printf("NULL\n");
}
//尾删
void ListPopBack(LTNode* phead)
{
assert(phead);
//暴力判定:头指针的下一个结点还是头结点,那么说明只有头结点
assert(phead->prev != phead);
//
//LTNode* tail = phead->prev;
//LTNode* tailprev = tail->prev;
//tailprev->next = phead;
//phead->prev = tailprev;
温柔判定:链表为空,也就是只剩头结点时,就不会再删除的情况
if (tail != phead)
{
free(tail);
}
tail = NULL;
//改写:
ListErase(phead->prev);
}
//头插
void ListPushFront(LTNode* phead, DataType x)
{
assert(phead);
/*LTNode* Next = phead->next;
LTNode* newnode = BuyNode(x);
phead->next = newnode;
newnode->prev = phead;
newnode->next = Next;
Next->prev = newnode;*/
//改写:
ListInsert(phead->next,x);
}
//头删
void ListPopFront(LTNode* phead)
{
assert(phead);
//LTNode* tail = phead->next;
//LTNode* tailnext = tail->next;
//
暴力判断:说明只有一个头结点
//assert(phead->next != phead);
//
//phead->next = tailnext;
//tailnext->prev = phead;
//free(tail);
//tail = NULL;
//改写
ListErase(phead->next);
}
//查找
LTNode* ListFind(LTNode* phead, DataType x)
{
assert(phead);
LTNode* cur = phead->next;
while (cur != phead)
{
if (cur->data == x)
{
return cur;
}
cur = cur->next;
}
return NULL;
}
//pos位置之前插入
void ListInsert(LTNode* pos, DataType x)
{
assert(pos);
LTNode* posprev = pos->prev;
LTNode* newnode = BuyNode(x);
posprev->next = newnode;
newnode->prev = posprev;
newnode->next = pos;
pos->prev = newnode;
}
//删除pos位置结点
void ListErase(LTNode* pos)
{
assert(pos);
//因为phead结点不存数据,所以pos不会指向phead,所以不用判断
LTNode* posnext = pos->next;
LTNode* posprev = pos->prev;
posprev->next = posnext;
posnext->prev = posprev;
free(pos);
pos = NULL;
}
test.c
#define _CRT_SECURE_NO_WARNINGS 1
#include"List.h"
testList1()
{
LTNode* plist = InitList();
ListPushBack(plist,1);//因为有头结点,所以不用改变头指针,总结:不改变头指针传一级,改变传二级
ListPushBack(plist,2);
ListPushBack(plist,3);
ListPushBack(plist,4);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
ListPopBack(plist);
ListPrint(plist);
//ListPopBack(plist);
//ListPushFront(plist,4);
//ListPrint(plist);
ListPopFront(plist);
ListPrint(plist);
//ListPopFront(plist);
//ListPopFront(plist);
//ListPopFront(plist);
//LTNode* pos = ListFind(plist,3);
//if (pos != NULL)
//{
// /*printf("%d\n",pos->data);*/
// ListInsert(pos, 20);
// ListErase(pos);
//}
//ListPrint(plist);
}
int main()
{
testList1();
return 0;
}
本文为带头节点双循坏链表,如有问题,请评论区多多评论^_^