目录
链表结构:
链表优缺点
优点:任何地方插入时间复杂度:都是O(1)
缺点:不支持随机读取,一些排序使用起来效率低;二分查使用不了(找不到中间下标)
链表实现
头文件
#pragma once
#include <stdio.h>
#include <assert.h>
#include <stdlib.h>
typedef int DLDataType;
typedef struct DListNode {
struct DLNode* next;
struct DLNode* prev;
DLDataType data;
}DLNode;
///创建新节点
DLNode* BuyListNode(DLDataType x);
///初始化
DLNode* DListInit();
///打印
void DListPrint(DLNode* phead);
///尾插
void DListPushBack(DLNode* phead,DLDataType dataval);
///头插
void DListPushFront(DLNode* phead, DLDataType dataval);
///尾删
void DListPopBack(DLNode* phead);
///头删
void DListPopFront(DLNode* phead);
///查找
DLNode* DListFind(DLNode* phead, DLDataType dataval);
///插入
void DListInesert(DLNode* pos, DLDataType dataval);
///删除
void DListErase(DLNode* pos);
初始化、新节点创建和打印
///创建新节点
DLNode* BuyListNode(DLDataType x)
{
DLNode* newNode = (DLNode*)malloc(sizeof(DLNode)); //创建新节点
if(newNode==NULL) //判断不为空
{
perror("neNode::malloc");
exit(-1);
}
newNode->next = NULL; // 初始化属性
newNode->prev = NULL;
newNode->data = x;
return newNode;
}
///初始化
DLNode* DListInit()
{
DLNode* phead = BuyListNode(-1); //生成头部;
phead->next = phead; //next是自己
phead->prev = phead; //prev是自己
return phead; //返回;如果不想返回,可以采用双指针写法,直接改变地址内容;
}
///打印
void DListPrint(DLNode* phead)
{
DLNode* curtail = phead->next; //(哨兵位))头部没有内容,内容是从下一个开始的
while (curtail != phead) //循环到哨兵位结束
{
printf("%d ", curtail->data);
curtail = curtail->next;
}
printf("\n");
}
头插
构思图
代码
///头插
void DListPushFront(DLNode* phead, DLDataType dataval)
{
//在head和head->next之间插入newNode
DLNode* newNode = BuyListNode(dataval);
DLNode* curtail = phead->next; //拿到第一个节点
//next.prev指向设定
newNode->next = curtail;
newNode->prev = phead;
curtail->prev = newNode;
phead->next = newNode;
//DListInesert(phead->next, dataval);
}
尾插
构思图
代码
///尾插
void DListPushBack(DLNode* phead,DLDataType dataval)
{
//获取最后一个节点,
DLNode* newNode = BuyListNode(dataval); //新建节点
DLNode* curtail = phead->prev; //获得尾部节点
newNode->next = phead;
newNode->prev = curtail;
curtail->next = newNode;
phead->prev = newNode;
//phead->prev 最后一个
//DListInesert(phead->prev, dataval); //inseret复用
}
头删
构思图
代码
///头删
void DListPopFront(DLNode* phead)
{
DLNode* curtail = phead->next; //拿到头
DLNode* prev = curtail->prev; //头的前一个
DLNode* next = curtail->next; //头的后一个
prev->next = next;
next->prev = prev;
//DListErase(phead->next);
}
尾删
构思图
代码
///尾删
void DListPopBack(DLNode* phead)
{
DLNode* curtail = phead->prev; //拿到尾
DLNode* prev = curtail->prev; //尾的前一个
DLNode* next = curtail->next; //尾的后一个
prev->next = next;
next->prev = prev;
free(curtail);
curtail = NULL;
//DListErase(phead->prev);
}
查找
///查找
DLNode* DListFind(DLNode* phead, DLDataType dataval)
{
DLNode* curtail = phead->next;
while (curtail != phead)
{
if (curtail->data == dataval)
return curtail;
curtail = curtail->next;
}
return NULL;
}
//从哨兵位->next开始,循环到哨兵位结束
插入
构思图
代码
///插入 在pos和pos->prev之间插入
void DListInesert(DLNode* pos, DLDataType dataval)
{
assert(pos);
DLNode* prev = pos->prev;
DLNode* newNode = BuyListNode(dataval);
prev->next = newNode;
pos->prev = newNode;
newNode->prev = prev;
newNode->next = pos;
}
删除
构思图
代码
///删除
void DListErase(DLNode* pos)
{
assert(pos);
DLNode* prev = pos->prev; //pos前一个
DLNode* next = pos->next;
//pos后一个
prev->next = next;
next->prev = prev;
free(pos);
pos = NULL;
}
销毁链表
///删除
void DListdestory(DLNode* pHead)
{
assert(pHead);
DLNode* cur= pHead->next; //拿到第一个存储数据的节点
while(cur != PHead)
{
DLNode* next = cur->next;//拿到当前节点的下一个节点
DListErase(cur); //删除
cur=next; //迭代
}
//释放哨兵头节点
free(pHead);
phead=NULL;
}
链表大小
///删除
void DListSize(DLNode* pHead)
{
assert(pHead);
DLNode* cur= pHead->next; //拿到第一个存储数据的节点
int size = 0;
while(cur != PHead)
{
++size;
cur=cur->next; //迭代
}
//释放哨兵头节点
return size;
}
带size版的链表
如果是需要高频率的访问链表的size,且量表数据量较大;建议使用带size版的;
仅仅是在外面加了一个结构体,每次删减对Size进行操作;