单链表——线性表链式存储结构的特点是:用一组任意的存储单元存储线性表的数据元素(这组存储单元可以是连续的,也可以是不连续的)。为了表示每个数据元素 a i a_i ai与其直接后继数据元素 之间的逻辑关系,对数据元素 a i a_i ai来说,除了存储其本身的信息之外,还需存储一个指示其直接后继的信息(即直接后继的存储位置)。 这两部分信息组成数据元素 a i a_i ai的存储映像,称为结点。
单链表的C语言实现
头文件
#include<stdio.h>
#include<stdlib.h>
//结果函数状态代码
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
#define MAXSIZE 100 //顺序表可能达到的最大长度
typedef int Status; // Status--函数的类型,其值是函数结果的状态代码
typedef char ElemType;
typedef struct LNode //声明节点类型和指向节点的指针类型
{
ElemType data; //节点的数据域
struct LNode *next; //节点的指针域
}Lnode, *LinkList; //LinkList为指向结构体Lnode的指针类型
单链表的初始化
Status InitList(LinkList L)
{
L = (LinkList)malloc(sizeof(Lnode)); //分配内存空间
L->next = NULL; //指针域置空
return OK;
}
判断链表是否为空
int ListEmpty(LinkList L)
{
//判断头指针是否为空即可
if(L->next) return 0; //非空返回0
else return 1; //空返回1
}
销毁单链表
Status DestroyList(LinkList L)
{
//从头指针开始,依次释放所有节点
Lnode *p;
while(L) //等价于 L!= NULL
{
p = L;
L = L->next;
printf("%c,",p->data);
free(p);
}
printf("删除成功\n");
return OK;
}
清空单链表
Status ClearList(LinkList L)
{
//依次释放所有节点,并将头结点指针域置空
Lnode *p, *q;
p = L->next;
while(p) //未到表尾
{
q = p->next;
free(p);
p = q;
}
L->next = NULL; //头结点指针域置空
return OK;
}
输出显示链表
void ShowList(LinkList L)
{
Lnode *p;
p = L->next; //p指向第一个节点
while(p) //遍历单链表
{
printf("%c,",p->data);
p = p->next;
}
printf("\n");
}
求链表表长
int GetLength(LinkList L)
{
//从首元结点开始,依次计数所有节点
Lnode *p;
p = L->next; //p指向第一个节点
int i = 0;
while(p) //遍历单链表,统计节点数
{
i++;
p = p->next;
}
return i;
}
获取链表第 i 个位置的元素,放入e中
Status GetElem(LinkList L, int i, ElemType *e)
{
Lnode *p = L->next; //初始化
int j = 1;
while(p&&j<i) //向后扫描,直到p指向第i个元素(j=i)或 p为空
{
p = p->next;
++j;
}
if(!p||j>i) return ERROR; //第i个元素不存在,位置非法
*e = p->data;
return OK;
}
按值查找,返回地址或位置, num存放位置, p存放地址
Status LocateElem(LinkList L, ElemType e, int *num, Lnode *p)
{
p = L->next;
int i = 1;
while(p && p->data!=e)
{
p = p->next;
i++;
}
*num = i+1;
if(p)
{
printf("%c\n",p->data);
return OK;
}
else return ERROR;
}
插入,在第i个节点前插入值为e的新节点
Status ListInsert(LinkList L, int i, ElemType e)
{
int j = 0;
Lnode *p = L;
Lnode *s = (LinkList)malloc(sizeof(Lnode));
while(p&&j<i-1) //寻找第 i-1个节点,p指向i-1节点
{
p = p->next;
++j;
}
if(!p || j>i-1) return ERROR; //i大于表长+1或小于1,插入位置非法
s->data = e;
s->next = p->next; //将节点 s 插入L中
p->next = s;
return OK;
}
删除第i个节点,利用e保存删除结点数据
Status ListDelete(LinkList L, int i, ElemType *e)
{
int j = 1;
Lnode *p = L->next;
Lnode *q;
while(p&&j<i-1) //寻找第 i-1个节点,p指向i-1节点
{
p = p->next;
++j;
}
if(!p || j>i-1) return ERROR; //i大于表长+1或小于1,删除位置非法
q = p->next; //临时保存被删除节点的地址以备释放
p->next = q->next; //改变 i-1节点的指针域,使其指向 i+1
*e = q->data; //保存删除节点的数据域
printf("删除成功, %c\n", *e);
free(q); //释放删除结点的空间
printf("%c所在地址为%d\n",*e, &e);
return OK;
}
单链表的创建----头插法
LinkList CreatList_Head(int n)
{
LinkList L;
L = (LinkList)malloc(sizeof(Lnode));
L->next = NULL; //创建带头结点的单链表
ElemType e = 'h';
int i;
for(i=n;i>0;i--) //(倒位序)从尾到头,插入n个数据
{
Lnode *p = (LinkList)malloc(sizeof(Lnode)); //生成新节点
p->data = e; //产生新元素
p->next = L->next; //插入到表头
L->next = p;
e--;
}
return L;
}
单链表的创建----尾插法
LinkList CreatList_Tail(int n)
{
LinkList L;
L = (LinkList)malloc(sizeof(Lnode));
L->next = NULL; //创建带头结点的单链表
Lnode *r = L; //尾指针r指向头结点
ElemType e = 'a';
int i;
for(i=0;i<n;i++)
{
Lnode *p = (LinkList)malloc(sizeof(Lnode)); //生成新节点
p->data = e; //产生新元素
p->next = NULL;
r->next = p; //插入到表尾
e++;
r = p ; //r指向新的尾结点
}
return L;
}
主函数
int main()
{
Status InitList(LinkList L); //单链表的初始化
int ListEmpty(LinkList L); //判断链表是否为空
Status DestroyList(LinkList L); //销毁单链表
Status ClearList(LinkList L); //清空单链表
int GetLength(LinkList L); //求链表表长
Status GetElem(LinkList L, int i, ElemType *e); //获取链表第 i 个位置的元素,放入e中
Status LocateElem(LinkList L, ElemType e, int *num, Lnode *p); //按值查找,返回地址或位置, num存放位置, p存放地址
Status ListInsert(LinkList L, int i, ElemType e); //在第i个节点前插入值为e的新节点
Status ListDelete(LinkList L, int i, ElemType *e); //删除第i个节点,利用e保存删除结点数据
void ShowList(LinkList L); //输出显示链表
LinkList CreatList_Head(int n); //单链表的创建----头插法
LinkList CreatList_Tail(int n); //单链表的创建----尾插法
int n = 8, i = 5, loc;
LinkList L;
InitList(L);
Lnode p;
L = CreatList_Tail(n); //尾查法创建链表;
if(!ListEmpty(L)) //判断链表是否为0
{
printf("非空\n");
}
else printf("空\n");
ShowList(L);
printf("链表表长为:%d\n", GetLength(L));
ElemType e, e1;
ListDelete(L, i, &e);
printf("删除第%d个节点的值为:%c\n", i, e);
ShowList(L);
ListInsert(L, i, e);
ShowList(L);
GetElem(L, i, &e1);
printf("第%d个节点的值为:%c\n", i, e1);
LocateElem(L, e, &loc, &p);
printf("首节点地址:%d\n",L->next);
printf("%c所在节点的位置为:%d,地址为%d\n", e, loc, &p);
ListInsert(L, 4, 'l');
ShowList(L);
//ShowList(L);
DestroyList(L);
}