单链表
1. 单链表的定义
单向不带头不循环链表
typedef int SLTDateType; //数据类型别名定义
typedef struct SListNode
{
SLTDateType data; //data用来储存数据
struct SListNode* next; //定义next指针用来链接
}SLTNode;
2. 创建节点
SLTNode* BuyListNode(SLTDateType x)
{
SLTNode* newnode =(SLTNode*)malloc(sizeof(SLTNode));
if(newnode == NULL)
{
printf("malloc fall\n");
exit(-1);
}
newnode->data = x;
newnode->next = NULL;
return newnode;
};
3. 打印链表
void SListPrint(SLTNode* phead){
SLTNode* cur = phead;
while (cur != NULL)
{
printf("%d",cur->data);
cur = cur->next;
}
printf("\n");
};
4. 尾插
void SListPushBack (SLTNode** pphead,SLTDateType x){ //传二级指针,通过改变形参来改变实参
assert(*pphead != NULL);
SLTNode* newnode = BuyListNode(x);
if(*pphead == NULL)
{
*pphead = newnode; //如果头指针为空,直接让头指针指向新结点
}
else
{
SLTNode* tail = *pphead;
while (tail->next != NULL) //找尾
{
tail = tail->next;
}
tail->next = newnode; //把尾结点接上新结点
}
};
5. 头插
void SListPushFront (SLTNode** pphead,SLTDateType x){
assert(*pphead != NULL);
SLTNode* newnode = BuyListNode(x);
newnode->next = *pphead; //新结点的next指向之前的头
*pphead = newnode; //再把头指针前移
};
6. 尾删
void SListPopBack(SLTNode** pphead){
assert(*pphead != NULL); //判断是否有数据可删
if((*pphead)->next == NULL) //如果链表只有一个结点
{
free(*pphead);
*pphead = NULL;
}
else
{
SLTNode* prev = NULL; //定义一个新的指针,来保存移动之前的地址
SLTNode* tail = *pphead;
while (tail->next != NULL)//找尾,且保存尾之前的结点位置到prev
{
prev = tail;
tail = tail->next;
}
free(tail);
tail = NULL;
prev->next = NULL; //删除尾节点,并且给新的尾节点next指针赋上空
}
};
7. 头删
void SListPopFront(SLTNode** pphead)
{
assert(*pphead != NULL);
SLTNode* prev = (*pphead)->next; //定义一个指针指向头节点后面那个节点
free(*pphead); //删除头节点
*pphead = prev; //将头指针指向新的头节点
};
8. 查找
SLTNode* SListFind(SLTNode* phead,SLTDateType x)
{
assert(phead != NULL);
SLTNode* cur = phead;
while (cur)
{
if(cur->data == x)
{
return cur;
}
else
{
cur = cur->next;
}
}
return NULL;
};
9. 在pos位置之前去插入一个节点
void SListInsert(SLTNode** pphead,SLTNode* pos,SLTDateType x)
{
assert(*pphead != NULL);
assert(pos != NULL);
SLTNode* newnode =BuyListNode(x);
if (*pphead == pos) //如果pos位置为头节点位置
{
newnode->next = *pphead;
*pphead = newnode;
}
else
{
SLTNode* posPrev = *pphead;
while (posPrev->next != pos) //找到pos位置的前一个节点位置,储存到posPrev里面
{
posPrev = posPrev->next;
}
posPrev->next = newnode;
newnode->next = pos;
}
}
10. 在pos位置之后去插入一个节点
void SListInsertAfter(SLTNode* pos,SLTDateType x)
{
assert(pos != NULL);
SLTNode* newnode = BuyListNode(x);
newnode->next = pos->next; //必须先让新节点的next先指向后面结点
pos->next = newnode; //再让pos的next指向新结点
};
11. 删除pos位置节点
void SListErase(SLTNode** pphead,SLTNode* pos)
{
assert(*pphead != NULL);
assert(pos != NULL);
if(*pphead == pos) //如果pos位置是头节点
{
*pphead = pos->next;
free(pos);
}
else
{
SLTNode *prev = *pphead; //找到pos位置的前一个节点位置,储存到prev里面
while (prev->next != pos)
{
prev = prev->next;
}
prev->next = pos->next; //将pos位置前一个节点和pos位置后一个节点链接
free(pos);
}
};
12. 删除pos位置的后面一个节点
void SListEraseAfter(SLTNode* pos)
{
assert(pos !=NULL);
assert(pos->next != NULL); //如果pos为尾节点
SLTNode* prev = pos->next;
pos->next = prev->next;
free(prev);
};
13. 链表的销毁
void SListDestory(SLTNode** pphead)
{
assert(*pphead != NULL);
SLTNode* cur = *pphead;
while (cur) //依次释放节点
{
SLTNode* prev = cur->next;
free(cur);
cur = prev;
}
*pphead = NULL; //头指针赋空
};
14. 单链表的优缺点
1. 优点
(1)存储空间动态分配,只要有内存空间,数据就不会溢出。
(2)便于实现插入与删除操作。
2. 缺点
(1)存储空间不一定连续,内容分散,有时会导致调试不便。
(2)每一个结点(除头结点)都有数据域与指针域,增大存储空间的开销。
(3)单链表查找结点时,需要从头开始查找,增加查找时间。