线性表之链表
本篇继上篇继续讲解链式存储的实现和操作方法
导航顺序表 链接放在此地
链表
特点:链表中相邻的的元素ai和ai+1在内存中位置LOC(ai)和LOC(ai+1)不一定是连续的,就是计算机内存内存地址是不一定连续(随机的)【具体参见下面的两种插入法】
定义补充
// filename : linklist.h
#ifndef __LINKLIST_H__
#define __LINKLIST_H__
typedef int ElemType;
typedef struct LNode{
ElemType data;
struct LNode *next;
}LNode, *LinkList;
void List_HeadInsert(LinkList *L);
void List_TailInsert(LinkList *L);
void Traverse_List(LinkList L);
LNode *GetElem(LinkList L, int i);
int ListLen(LinkList L);
void List_InsertNode(LinkList *L,int i, ElemType e);
ElemType List_DeleteNode(LinkList *L, int i);
#endif
对链表进行初始化
链表初始化分为两种:头插法和尾插法
头插法
头插法:顾名思义 就是每一个新的节点就插入到头节点后面第一个数据节点的后面 此方法初始化 是逆序的
具体见下图
代码实现
// filename : main.c
void List_HeadInsert(LinkList *L)
{
int x;
LNode *s;
*L = (LinkList)malloc(sizeof(LNode));
if (*L == NULL){
fprintf(stderr, "malloc() fail,line:%d\n", __LINE__);
exit(1);
}
(*L)->next = NULL;
fscanf(stdin, "%d", &x);
while (x != 9999)
{
s = (LinkList)malloc(sizeof(LNode));
if (s == NULL){
fprintf(stderr, "malloc() fail,line:%d\n", __LINE__);
exit(1);
}
s->data = x;
s->next = (*L)->next;
(*L)->next = s;
fscanf(stdin, "%d", &x);
}
}
尾插法
尾插法:顾名思义 就是每一个新节点都插入到尾节点的后面(即插入到最后) 此方法初始化 是顺序的
具体见下图
代码实现
// filename : main.c
void List_TailInsert(LinkList *L)
{
int x;
LNode *s = NULL;
LNode *pN = NULL;
*L = (LinkList)malloc(sizeof(LNode));
if (*L == NULL)
{
fprintf(stderr, "malloc() line:%d\n", __LINE__);
exit(1);
}
(*L)->next = NULL;
pN = (*L);
fscanf(stdin, "%d", &x);
while(x != 9999)
{
s = (LinkList)malloc(sizeof(LNode));
if (s == NULL)
{
fprintf(stderr,"malloc() line:%d\n", __LINE__);
exit(1);
}
s->data = x;
s->next = NULL;
pN->next = s;
pN = pN->next;
fscanf(stdin, "%d", &x);
}
}
链表的遍历
实现思路:由于每一个节点都指向下一个节点,而最后一个节点的指针域是NULL,通过while去判断当前接待你的指针域是否为NULL , 这就是我们的遍历思路
具体实现如下
代码实现
// filename : main.c
void Traverse_List(LinkList L)
{
LNode* pN = NULL;
pN = L->next;
while(pN != NULL)
{
printf("%d->", pN->data);
pN = pN->next;
}
printf("NULL\n");
}
获取链表长度
实现思路:获取长度跟链表的遍历差不离儿 在遍历的基础上增加一个计数器,每循环一次加一
具体实现如下
// filename : main.c
int ListLen(LinkList L)
{
LNode *pN = L->next;
int len = 0;
while (pN != NULL)
{
len++;
pN = pN->next;
}
return len;
}
获取指定位置的节点
实现思路:通过遍历,增加计数器,和给出i比较,如果相等退出循环 返回当前的节点,如果不相等改变指针指向下一个位置
具体实现如下
// filename : main.c
LNode *GetElem(LinkList L, int i)
{
if (i < 1 && ListLen(L) > i)
{
fprintf(stderr, "GetElem parameter i error line:%d\n", __LINE__);
exit(1);
}
int count = 1;
LNode *pN = L->next;
while (pN != NULL)
{
if (count++ == i)
{
return pN;
}
else
{
pN = pN->next;
}
}
}
向链表中指定位置插入一个节点
实现思路:获取要插入节点的前一个节点,创建一个新的节点, 改变前一个指针的指向,在此要改变指针的先后顺序,防止链表断开,首先令新的节点指向要插入位置的节点,然后在改变插入位置前一个位置的指针
具体实现如下
void List_InsertNode(LinkList *L,int i, ElemType e)
{
if (i < 1 && ListLen(*L) > i)
{
fprintf(stderr, "List_InsertNode() parameter i error line:%d\n", __LINE__);
exit(1);
}
LNode *s = (LinkList)malloc(sizeof(LNode));
if (s == NULL)
{
fprintf(stderr, "malloc() error line:%d\n", __LINE__);
exit(1);
}
LNode *pN = GetElem(*L, i-1);
s->data = e;
s->next = pN->next;
pN->next = s;
}
删除指定位置的节点
实现思路:找到要删除节点的前一个节点,更改前一个节点的指针指向要删除位置节点的下一个节点,注意c语言要释放掉内存空间
具体实现如下
ElemType List_DeleteNode(LinkList *L, int i)
{
if (i < 1 && ListLen(*L) > i)
{
fprintf(stderr, "List_DeleteNode() parameter i error line:%d\n", __LINE__);
exit(1);
}
ElemType e;
LNode *qN = NULL;
LNode *pN = GetElem(*L, i-1);
qN = pN->next;
e = qN->data;
pN->next = qN->next;
free(qN);
return e;
}
代码地址 阿里云盘地址:https://www.aliyundrive.com/s/kVhr2EpQ5Dg 提取码:7zr2