链表中通常都是包含两部分,一个数据域,一个指针域。前者用于存储所需要的各种数据,后者用于存储后继结点的地址。通常有一个头指针指向链表的头结点,然后头结点的指针域指向第一个结点,最后一个结点的指针域为NULL,表示后面没有了。相比于顺序表,链表的每个结点数据所占的内存可以分布在计算机内存的各个角落,需要时动态分配。
逆序创建单链表
void CreateList_L(LinkList &L, int a[], int n)
创建单链表时,首先定义链表这一数据结构,然后再定义单链表变量。其实再定义变量时链表就已经建好了,而CreateList_L函数的本质是对这个链表赋值。即先把想存到单链表里的数据存储到数组里,然后再转存到链表里。要先定义一个指向新建立结点的指针,然后通过循环对这个结点赋值,再将L头指针指向这个新建立的结点。头插法,即把每一个新结点都插入到第一个结点之前。
求链表的长度
int ListLength_L(LinkList L)
定义一个指向结点的指针,先让它指向头结点,然后往后遍历,同时k加一。while循环遍历时限制条件是while(p);确保p指向最后一个结点时也能计数。利用指针遍历链表时指针p不能是p++,而要使p=p->next;!!!
查找元素 返回其地址
LNode *LocateElem_L(LinkList L, int e)
同样是要定义一个指针来遍历链表,while循环的限制条件是while(p&&p->next!=e) 最后返回p指针。如果没有这个元素则p==NULL;
插入节点操作
void ListInsert_L(LinkList &L, LNode *p, LNode *s)
再L为头指针的链表中,将结点s插入到结点p之前。首先判断p是否为头结点,若不是则创建一个指针q遍历,while(q->next!=p) 当跳出这个循环时q指向p的前驱结点,此时再让新建结点s指向p,然后让q指向结点s.
删除结点
int ListDelete_L(LinkList &L, LNode *p)
定义指针q用于遍历链表,然后判断p是否是头结点,如果是则直接改变头结点,L=L->next;如果不是,则用q遍历,直到q指向p的前驱结点,然后改变q的指针域。q->next=p->next; 将结点p的值赋给e,最后删除结点p。
写在最后
链表类似与顺序表但有所不同。首先,链表无法利用下标进行索引,所以如果要进行遍历的话要定义指针p,然后让指针p=p->next;注意,不能直接p++!!!然后是关于函数的形参部分,创建,插入,删除等操作要改变链表本身,所以定义函数时形参里要用LinkList &L; 求链表长度,查找元素等操作都不需要改变链表本身,所以函数的形参里用LinkList L;
上述操作的代码如下:
#include<stdio.h>
typedef struct LNode {
int data;
struct LNode *next;
}LNode,*LinkList;
/************************************************************************************
逆序创建单链表,即每个新结点都插在最前面 创建
************************************************************************************/
void CreateList_L(LinkList &L, int a[], int n)
{
//数组a[n]中存有链表需要的数据元素,逆序创建单链表L
int i;
LNode *s; //s为指向新建立的结点的指针
L = NULL;
for (i = n - 1; i >= 0; i--)
{
s = new LNode; //生成新结点
s->data = a[i]; //给新结点赋值
s->next = L;
L = s; //将新结点插入在第一个节点之前
}
}
/*************************************************************************************
求单链表的长度 求长度
**************************************************************************************/
int ListLength_L(LinkList L)
{
//L为头指针 函数返回L所指链表的长度
LNode *p=L;
int k = 0;
while (p)
{
k++;
p = p->next;
}
return k;
}
/*****************************************************************************************
查找元素操作 返回第一个与e相等的元素在单链表中的位置 查找
******************************************************************************************/
LNode *LocateElem_L(LinkList L, int e)
{
//由于要返回位置,所以直接返回一个指向目标数据的指针
LNode *p = L;
while (p&&p->data != e)
p = p->next;
return p;
}
/*******************************************************************************************
插入结点操作 插入
********************************************************************************************/
void ListInsert_L(LinkList &L, LNode *p, LNode *s) //此处&L一定不能省略!!!!!
{
//指针p指向L为头指针的链表中某个结点,将s结点插入到p结点之前
if (p == L)
{
s->next = L;
L = s;
}
else
{
LNode *q = L;
while (q->next!=p)
q = q->next; //当跳出while循环时,q指针已经指向p结点的前驱结点的位置
q->next = s;
s->next = p;
}
}
/*********************************************************************************************
删除结点的操作 删除p所指的结点,并用e返回其值 删除
**********************************************************************************************/
int ListDelete_L(LinkList &L, LNode *p)
{
int e;
LNode *q; //用于遍历链表
if (p == L)
L = L->next;
else
{
q = L;
while (q->next != p)
q = q->next; //跳出循环时q指向目标结点的前驱结点
q->next = p->next;
}
e = p->data;
delete p;
return e;
}
/*********************************************************************************************
主函数
**********************************************************************************************/
void main()
{
int a[10] = { 1,2,3,4,5,6,7,8,9,10 };
int length;
LNode *p;
LinkList L;
CreateList_L(L, a, 10);
printf("新建立的单链表:");
for (p = L; p != NULL; p = p->next)
printf("%d ", p->data);
printf("\n");
length = ListLength_L(L);
printf("该链表的长度为%d.", length);
printf("\n");
printf("在链表中查找数据6:");
if (LocateElem_L(L, 6))
printf("存在目标元素,已确定其地址,数值为%d.", LocateElem_L(L, 6)->data);
else
printf("目标元素不存在");
printf("\n");
LNode *s,*n=L;
s = new LNode;
s->data = 12;
printf("新建结点s,数据域存储12,插入到链表第一个结点之前,插入后的链表为:");
ListInsert_L(L, n, s);
for (p = L; p != NULL; p = p->next)
printf("%d ", p->data);
printf("\n");
printf("删除链表的第一个元素,返回值为%d,删除后链表为:", ListDelete_L(L,L));
for (p = L; p != NULL; p = p->next)
printf("%d ", p->data);
}
程序运行结果如下:
本笔记所依据的教材为严薇敏版的《数据结构及应用算法教程》
所有代码在Visual Studio 2017上均可正常运行
如有错误欢迎指出