目录
参考材料与格式
线性表的有关知识
头文件
库、宏定义、数据类型声明
线性表的双向链表存储结构
构造空链表
销毁链表
链表长度
按位查找
插入元素
删除元素
打印链表
完整头文件DuLinkList.h
测试函数(主函数)
测试结果
收获
参考材料与格式
参考材料:数据结构(C语言版)严蔚敏 吴伟民编著。
线性表的有关知识
预习到这里,有点感觉概念有点多,线性表,顺序表,链表,单链表,双向链表,静态链表,动态链表,循环链表......有的链表只有头指针,有的链表头指针尾指针都有,有的只有尾指针,那么怎么区分这些概念呢?从头说起。
线性表是数据结构,数据结构是相互之间一种或多种特定关系的数据元素的集合。顺序表与链表都是物理结构,又称存储结构,存储结构包括数据元素的表示和关系的表示。存储结构是数据结构在计算机中的表示,举个例子,可以说,单链表是线性表在计算机中表示的一种方式。所以,2.2节的标题是线性表的顺序表示与实现,意思是,这一节讲用顺序表表示线性表(线性表的顺序表示),用类C代码实现顺序表。
这些概念有一个特点,都是成对出现。如顺序表与链表、单链表与双向链表、静态链表与动态链表、循环链表与非循环链表......这些概念每一对都有且只有一个,如本节实现的存储结构为双向 循环 动态 链表,只有头指针。
为什么说这么多呢?因为课本中虽然单独介绍循环链表(35页2.3.2节),但后面没跟上代码,我一想,静态链表也可以循环,单链表、双向链表也可以循环,所以还是先弄清楚概念,再怎么写文章也不迟。
头文件
库、宏定义、数据类型声明
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;//Status是函数的类型,其值是函数结果状态代码
typedef int ElemType;
线性表的双向链表存储结构
//-----线性表的双向链表存储结构-----
typedef struct DuLNode {
ElemType data;
struct DuLNode* prior;
struct DuLNode* next;
}DuLNode,*DuLinkList;
构造空链表
Status InitList_DuL(DuLinkList& L) {
//构造一个空的线性链表L
L = (DuLinkList)malloc(sizeof(DuLNode));
L->prior = L->next = L;
return OK;
}
销毁链表
Status DestroyList_DuL(DuLinkList& L) {
//销毁线性链表L,L不再存在
DuLinkList p = L;
while (L->next != L) {
L->next->prior = L->prior;
L->prior->next = L->next;
L = L->next;
free(p);
p = L;
}
free(L);
return OK;
}
链表长度
int ListLength_DuL(DuLinkList L) {//求链表长度
DuLinkList p = L->next;
int count = 0;
while (p != L)
{
p = p->next;
count++;
}
return count;
}//一定要在GetElem_DuL函数前面
代码写完调试时,报错,找不到标识符,下面是解决文章。
如何解决VC2019中:error C3861: “xxxx”: 找不到标识符_error c3861 pow 找不到标识符-CSDN博客
简单总结,因为我的GetElem_DuL函数调用了这个求链表长度的函数,如果Get这个函数在前面的话,Get函数内部的求链表长度函数没有定义,出现C3861问题。解决方法有二,一是像注释中写的将求链表长度的函数放在前面,二是将求链表长度的函数写函数声明。
按位查找
DuLinkList GetElem_DuL(DuLinkList L, int i) {
//L为带头结点的单链表的头指针。
//按位查找
DuLinkList p = L;
if (i >= 1 && i <= ListLength_DuL(L) + 1) {
int m = i;
while (m--) {
p = p->next;
}
}
else
p = NULL;
return p;
}
插入元素
//算法2.18 插入元素
Status ListInsert_DuL(DuLinkList& L, int i, ElemType e) {
//在带头结点的双链循环线性表L中第i个位置之前插入元素e,即在p前面插入结点
//i的合法值为1<=i<=表长+1。
DuLinkList p, s;//曾试过变量p,s一边声明一边赋值,结果报错,不知道为什么。
if (!(p = GetElem_DuL(L, i)))//在L中确定插入位置指针p
return ERROR;//i等于表长加1时,p指向头结点;i大于表长加1时,p=NULL。
if (!(s = (DuLinkList)malloc(sizeof(DuLNode))))
return ERROR;
s->data = e;
s->prior = p->prior;p->prior->next = s;
s->next = p;p->prior = s;
return OK;
}
删除元素
//算法2.19 删除元素
Status ListDelete_DuL(DuLinkList& L, int i, ElemType& e) {
//删除带头结点的双链循环线性表L的第i个元素,i的合法值为1<=i<=表长
DuLinkList p;
if (!(p = GetElem_DuL(L, i)))//在L中确定第i个元素的位置指针p
return ERROR;//p=NULL,即第i个元素不存在
e = p->data;
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
return OK;
}
打印链表
void PrintList_DuL(DuLinkList L) {//打印链表
DuLinkList p = L->next;
while (p != L) {//注意与单链表的有区别,单链表是p!=NULL
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
完整头文件DuLinkList.h
#pragma once
#include <cstdio>
#include <cstdlib>
#include <cstring>
#define TRUE 1
#define FALSE 0
#define OK 1
#define ERROR 0
#define INFEASIBLE -1
#define OVERFLOW -2
typedef int Status;//Status是函数的类型,其值是函数结果状态代码
typedef int ElemType;
//-----线性表的双向链表存储结构-----
typedef struct DuLNode {
ElemType data;
struct DuLNode* prior;
struct DuLNode* next;
}DuLNode,*DuLinkList;
Status InitList_DuL(DuLinkList& L) {
//构造一个空的线性链表L
L = (DuLinkList)malloc(sizeof(DuLNode));
L->prior = L->next = L;
return OK;
}
Status DestroyList_DuL(DuLinkList& L) {
//销毁线性链表L,L不再存在
DuLinkList p = L;
while (L->next != L) {
L->next->prior = L->prior;
L->prior->next = L->next;
L = L->next;
free(p);
p = L;
}
free(L);
return OK;
}
int ListLength_DuL(DuLinkList L) {//求链表长度
DuLinkList p = L->next;
int count = 0;
while (p != L)
{
p = p->next;
count++;
}
return count;
}//一定要在GetElem_DuL函数前面
DuLinkList GetElem_DuL(DuLinkList L, int i) {
//L为带头结点的单链表的头指针。
//按位查找
DuLinkList p = L;
if (i >= 1 && i <= ListLength_DuL(L) + 1) {
int m = i;
while (m--) {
p = p->next;
}
}
else
p = NULL;
return p;
}
//算法2.18 插入元素
Status ListInsert_DuL(DuLinkList& L, int i, ElemType e) {
//在带头结点的双链循环线性表L中第i个位置之前插入元素e,即在p前面插入结点
//i的合法值为1<=i<=表长+1。
DuLinkList p, s;//曾试过变量p,s一边声明一边赋值,结果报错,不知道为什么。
if (!(p = GetElem_DuL(L, i)))//在L中确定插入位置指针p
return ERROR;//i等于表长加1时,p指向头结点;i大于表长加1时,p=NULL。
if (!(s = (DuLinkList)malloc(sizeof(DuLNode))))
return ERROR;
s->data = e;
s->prior = p->prior;p->prior->next = s;
s->next = p;p->prior = s;
return OK;
}
//算法2.19 删除元素
Status ListDelete_DuL(DuLinkList& L, int i, ElemType& e) {
//删除带头结点的双链循环线性表L的第i个元素,i的合法值为1<=i<=表长
DuLinkList p;
if (!(p = GetElem_DuL(L, i)))//在L中确定第i个元素的位置指针p
return ERROR;//p=NULL,即第i个元素不存在
e = p->data;
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
return OK;
}
void PrintList_DuL(DuLinkList L) {//打印链表
DuLinkList p = L->next;
while (p != L) {//注意与单链表的有区别,单链表是p!=NULL
printf("%d ", p->data);
p = p->next;
}
printf("\n");
}
测试函数(主函数)
#include "DuLinkList.h"
int main()
{
DuLinkList L;
Status i;
ElemType e;
i = InitList_DuL(L);
if (!i)
printf("构造成功!\n");
else
printf("构造失败!\n");
i = ListInsert_DuL(L, 0, 13);
if (!i)
printf("插入失败。\n");
else
printf("插入的元素为13。\n");
for (int j = 5;j <= 10;j++) {
i = ListInsert_DuL(L, 1, j);
if (!i)
printf("插入失败。\n");
else
printf("插入的元素为%d。\n",j);
}
i = ListInsert_DuL(L, 7, 13);
if (!i)
printf("插入失败。\n");
else
printf("插入的元素为13。\n");
i = ListInsert_DuL(L, 9, 13);
if (!i)
printf("插入失败。\n");
else
printf("插入的元素为13。\n");
PrintList_DuL(L);
i = ListDelete_DuL(L, 7, e);
if (!i)
printf("删除失败\n");
else
printf("删除的元素为%d。\n", e);
i = ListDelete_DuL(L, 3, e);
if (!i)
printf("删除失败\n");
else
printf("删除的元素为%d。\n", e);
PrintList_DuL(L);
DestroyList_DuL(L);
return 0;
}
测试结果
收获
1、弄清了本章一些概念的联系。
2、解决了找不到标识符的问题。