概念:链表是一个物理上非连续存储,非顺序的数据结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的
在链表中我们最常用的还是两种数据结构:
1.无头单向非循环链表:结构简单,一般来说不会单独用来存放数据。实际中更多是作为其他数据结构的子结构,如哈希桶,图的邻接图等等。另外这种数据结构在笔试面试中出现的很多。
2.带头双向循环链表:结构最复杂,一般用在单独的存储数据。实际中使用的链表数据结构,都是带头双向循环链表。另外这个结构虽然复杂,但是使用代码实现后会发现结构带来很多优势,实现反而简单,下篇我们实现代码就知道了。
无头单向非循环链表的实现:我们也以类似工程的方式进行实现:
SList.h:函数声明
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
typedef int SLNDataTypa;
//定义一个结构体,里面包含一个结构体指针
typedef struct SListNode
{
SLNDataTypa val;
struct SListNode* next;
}SLNode;
//链表打印
void SLTPrint(SLNode*phead);
//链表尾插 //对形参的改变需要传地址
void SLTPushBack(SLNode** pphead, SLNDataTypa x);
//链表头插
void SLTPushFront(SLNode**pphead, SLNDataTypa x);
//链表尾删
void SLTPopBack(SLNode** pphead);
//链表头删
void SLTPopFront(SLNode** pphead);
//链表查找
SLNode* SLTFind(SLNode* plist, SLNDataTypa x);
//在pos位置之前插入
void SLTInsert(SLNode**pphead, SLNode* pos,SLNDataTypa x);
SList.c 函数定义
#include"SList.h"
//链表打印
void SLTPrint(SLNode*phead)
{
SLNode* cur = phead;
while (cur != NULL)
{
printf("%d->", cur->val);
cur = cur->next;
}
printf("NULL\n");
}
//创建节点
SLNode* CreateNode(SLNDataTypa x)
{
SLNode* newnode = (SLNode*)malloc(sizeof(SLNode));
if (newnode == NULL)
{
perror("mallo fail");
exit(-1);
}
newnode->val = x;
newnode->next = NULL;
return newnode;
}
//链表尾插
void SLTPushBack(SLNode** pphead, SLNDataTypa x)
{
//找尾
SLNode* newnode = CreateNode(x);
if (*pphead == NULL)
{
*pphead =newnode;
//改变结构体外面的指针node*
//需要用二级指针node**
}
else
{
//找尾
SLNode* tail = *pphead;
while (tail->next != NULL)
{
tail = tail->next;
}
tail->next = newnode;
}
}
//链表头插
void SLTPushFront(SLNode**pphead, SLNDataTypa x)
{
SLNode* newnode = CreateNode(x);
newnode->next = *pphead;
*pphead = newnode;
}
//链表尾删
void SLTPopBack(SLNode** pphead)
{
//空
assert(*pphead);
//一个节点,多个节点
if ((*pphead)->next == NULL)
{
free(*pphead);
*pphead = NULL;
}
else
{
SLNode* tail = *pphead;
SLNode* prev = NULL;//*pphead ; //=*pphead的话,一个指针后面free掉tail的时候,变为野指针了
while (tail->next != NULL)
{
prev = tail;
tail = tail->next;
}
free(tail);
tail = NULL; //好习惯,出作用域访问不到
prev->next = NULL;
}
}
//不需要prev
//while (tail->next->next != NULL)
//{
// tail = tail->next;
//}
//free(tail->next);
//tail->next = NULL;
//链表头删
void SLTPopFront(SLNode** pphead)
{
assert(*pphead);
//一个节点,即以上都能处理
SLNode* tmp = (*pphead)->next;
free(*pphead);
*pphead = tmp;
}
//链表查找
SLNode* SLTFind(SLNode* pphead, SLNDataTypa x)
{
assert(pphead);
SLNode* cur = pphead;
while (cur)
{
if (cur->val == x)
{
return cur;
}
else
{
cur = cur->next;
}
}
return NULL;
}
//在pos位置之前插入
void SLTInsert(SLNode**pphead, SLNode* pos, SLNDataTypa x)
{
assert(pphead);
//assert(*pphead);
//两个都是空,要么都不是空
assert((!pos && !(*pphead)) || (pos && *pphead));
if (*pphead == pos)
{
SLTPushFront(pphead, x);
}
else
{
SLNode* prev = *pphead;
while (prev->next != pos)
{
prev = prev->next;
}
SLNode* newnode = CreateNode(x);
prev->next = newnode;
newnode->next = pos;
}
}
test.c:
#include"SList.h"
void test1()
{
//尾插
SLNode* plist = NULL;
SLTPushBack(&plist, 1);
SLTPushBack(&plist, 2);
SLTPushBack(&plist, 3);
SLTPushBack(&plist, 4);
SLTPrint(plist);
//头插
SLTPushFront(&plist, 2);
SLTPrint(plist);
//尾删
SLTPopBack(&plist);
SLTPrint(plist);
SLTPopBack(&plist);
SLTPrint(plist);
//头删
SLTPopFront(&plist);
SLTPrint(plist);
//查找
SLNode*pos=SLTFind(plist,2);
//插入
SLTInsert(&plist, pos,20);
SLTPrint(plist);
pos = SLTFind(plist, 1);
SLTInsert(&plist, pos, 40);
SLTPrint(plist);
}
int main()
{
test1();
}