2.3.1 线性表的链式存储结构——链表
链表:
1.每个节点中除数据域外,设置了一个指针域,用以指向其后继节点,这样构成的链接表称为线性单向链表,简称单链表。
2.每个节点中除数据域外,设置两个指针域,分别用以指向其前驱节点和后继节点,这样构成的链表称为线性双向链接表,简称双链表。
在线性表的链式存储中,为了便于插入和删除算法的实现,每个链表带有一个头节点,并通过头节点的指针唯一标识该链表。
单链表LinkList类型定义如下:
typedef struct LNode//定义单链表节点类型
{
ElemType data;//存放元素值
struct LNode *Next;//指向后继节点
}
双链表DNode类型的定义如下:
typedef struct DNode
{
ElemType data;
struct DNode *prior;
struct DNode *next;
}
所谓存储密度是指节点数据本身所占的存储量和整个节点结构中所占存储量之比,即:
存储密度=节点数据本身所占的存储量/节点结构所占的存储总量
一、线性表基本运算在单链表中的实现:
需要注意的几个问题:
1、头节点的序号为0,且头节点不计入单链表的长度中;
2、开始节点的序号为1;
头插法建立单链表 :
void CreateListF(LinkList *&L, ElemType a[], int n)//头插法建立单链表
{
LinkList *s;
int i;
L->next = NULL;
L = (LinkList *)malloc(sizeof(LinkList));
for (i = 0;i < n;i++)
{
s = (LinkList *)malloc(sizeof(LinkList));
s->data = a[i];
s->next = L->next;
L->next = s;
}
}
尾插法建立单链表
void CreateListR(LinkList *&L, ElemType a[], int n)//尾插法建立单链表
{
LinkList *s,*r;
int i;
L = (LinkList *)malloc(sizeof(LinkList));
r = L;
for (i = 0;i < n;i++)
{
s = (LinkList *)malloc(sizeof(LinkList));
s->data = a[i];
r->next = s;
r = s;
}
r->next = NULL;
}
二、实践
1.在VS中创建VC++解决方案,并给方案命名为:单链表
2.在弹出对话框中选择“下一步”,其他为默认,选择“空项目”,然后点击“完成”
3.在资源管理器中,选择解决方案,点击右键,添加新建项,给新建项命名为:LNode.cpp
在文件中输入如下代码:
#include <stdio.h>
#include <malloc.h>
//----------线性表的动态分配链存储结构-------------
#define LIST_INT_SIZE 100
#define LISTINCREATMENT 10
#define OVERFLOW - 2
#define OK 1
#define ERROR 0
typedef int status;
typedef int ElemType;
typedef struct LNode {
ElemType data; //存储的元素;
struct LNode *next; //指向下一个节点;
}LNode, *LinkList;
status GetElem_L(LinkList L, int i, ElemType &e) {
//L为带头结点的单链表的头指针;
//当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR
LNode *p = L->next; //初始化,p指向第一个结点,j为计数器;
int j = 1;
while (p&&j < i) {//顺指针向后查找,直到p指向第i个元素或p为空
p = p->next;
++j;
}
if (!p || j>i) return ERROR;//第i个元素不存在
e = p->data;//取第i个元素
return OK;
}
status ListInsert_L(LinkList &L, int i, ElemType e) {
//在带头结点的单链线性表L中第i个位置之前插入元素e
LinkList p = L;
int j = 0;
while (p&&j < i - 1) {//寻找第i-1个结点
p = p->next;
++j;
}
if(!p||j>i-1) return ERROR;
LinkList s = (LinkList)malloc(sizeof(LNode));//生成新结点
s->data = e;
s->next = p->next;//插入L中
p->next = s;
return OK;
}
status ListDelete_L(LinkList &L, int i, ElemType &e) {
//在带头结点的单链表L总,删除第i个元素,并由e返回其值。
LinkList p = L;
int j = 0;
while (p->next&&j < i - 1) {//寻找第i个结点,并令p指向其前驱
p = p->next;
++j;
}
if (!(p->next) || j>i - 1) return OK;
LinkList q = p->next;//删除并释放结点
p->next = q->next;
e = q->data;free(q);
return OK;
}
void CreateList_L(LinkList &L, int n) {
//逆位序输入n个元素的值,建立带表头结点的单链表L
L = (LinkList)malloc(sizeof(LNode));
L->next = NULL;//先建立一个带头结点的单链表。
LinkList p;
for (int i = n;i > 0; --i) {
p = (LinkList)malloc(sizeof(LNode));//生成新结点
scanf_s("%d",&p->data);//输入元素值
p->next = L->next;//插入到表头
L->next = p;
}
}
void DisplayList(LinkList L) {
while (L->next) {
printf("%3d", L->next->data);
L = L->next;
}
}
void main() {
LinkList L;
CreateList_L(L, 5);
DisplayList(L);
}