因为教材是用的C++,所以今天的代码是用C++实现的
//单链表的定义
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
//初始化
Status InitList(LinkList &L)
{
L=new LNode;
L->next=NULL;
return OK;
}
//取值
Status GetElem(LinkList L ,int i,ElemType &e){
p=L->next;;
j=1;
while(p&&jnext;
++j;
}
if(!p||j>i)return ERRPR;
e=p->data;
return OK;
}
//查找
LNode *LocateElem(LinkList L,ElemType e){
p=L->next;
while(p && p->data!=e)
p=p->next;
return p;
}
//插入
Status ListInsert(LinkList &L,int i,ElemType e){
p=L;
j=0;
while(p && (jnext;
++j;
}
if(!p||j>i-1) return ERROR;
s=new LNode;
s->data=e;
s->next=p->next;
p->next=s;
return OK;
}
//删除
Status ListDelete(LinkList &L,int i){
p=L;
j=0;
while((p->next) && (jnext;
}
if(!(p->next)||j>i-1) return ERROR;
q=p->next;
p->next=q->next;
delete q;
return OK;
}
//前插法创建单链表
void CreateList_H(LinkList &L,int n){
L=new LNode;
L->next=NULL;
for(i=0;i>p->data;
p->next=L->next;
L->next=p;
}
}
//后插法创建单链表
void CreateList_R(LinkList &L,int n){
L=new Lnode;
L->next=NULL;
r=L;
for(i=0;i>p->data;
p->next=NULL;
r->next=p;
r=p;
}
}
//循环链表的定义及初始化
typedef struct LNode
{
ElemType data;
struct LNode *next;
}LNode,*LinkList;
Status InitList(LinkList &L)
{
L=new LNode;
L->next=L; //只有这里跟单链表不同,其余地方都一样
return OK;
}
//双向链表的定义及初始化
typedef struct DuLNode{
ElemType data;
struct DuLNode *prior;
struct DuLNode *next;
}DuLNode,*DuLinkList;
Status InitList(DuLinkList &L){
L=new DuLNode;
L->next=L;
L->prior=L;
return OK;
}
//双向链表的插入
Status ListInsert_DuL(DuLinkList &L,int i,ElemType e){
if(!(p=GetElem_Dul(L,i)))
return ERROR;
s=new DuLinkList;
s->data=e;
a=p->prior;
p->prior=s;
s->prior=a;
a->next=s;
s->next=p;
return OK;
}
//双向链表的删除
Status ListDelete_DuL(DuLinkList &L,int i){
if(!(p=GetElem_Dul(L,i)))
return ERROR;
p->next->prior=p->prior;
p->prior->next=p->next;
delete p;
return OK;
}
在一个链表中,每个节点都有一个 next
指针,指向下一个节点。例如,假设有两个节点:
LNode *node1 = new LNode;
LNode *node2 = new LNode;
node1->next = node2; // node1 的 next 指向 node2
在这个例子中,node1
的 next
指向 node2
,表示链表中的第一个节点指向第二个节点。通过这种方式,节点可以连接起来,形成一个链表。
这行代码 LNode *node1 = new LNode;
的意思是动态创建一个新的 LNode
类型的节点,并将其地址赋值给指针 node1
。
new LNode
:
new
是一个运算符,用于在堆上动态分配内存。LNode
表示你要创建一个新的 LNode
结构体实例。这段代码会在堆上分配足够的内存来存储一个 LNode
的数据,并返回这个新创建对象的地址。函数定义:
Status InitList(LinkList &L)
: 这是函数的声明,函数名为 InitList
,返回类型为 Status
(表示操作的状态,如成功或失败),接受一个引用类型的参数 LinkList &L
。这里的 LinkList
是指向 LNode
的指针类型。
创建新的节点:
L=new LNode;
: 这一行代码使用 new
关键字在堆上动态分配一个新的 LNode
结构的内存,并将这个新节点的地址赋值给 L
。这意味着 L
现在指向一个新的链表节点。
初始化 next
指针:
L->next=NULL;
: 将新节点的 next
指针设置为 NULL
,表示当前链表中只有一个节点(头节点),而且没有后继节点。链表的末尾通常用 NULL
来表示。
返回状态:
return OK;
: 函数结束时返回一个状态值 OK
,表示链表成功初始化。
LinkList
:这是一个指向 LNode
类型的指针(即 LNode*
的别名)。&L
:表示 L
是 LinkList
类型的引用。这意味着 L
引用的是一个指向 LNode
的指针。在 C++ 中,引用是一种特殊的变量,它允许你直接访问另一个变量的内存,而不是创建该变量的副本。当你使用引用作为参数时,函数可以直接操作传入的变量,而不需要返回值来修改它。(可以对比上个笔记C语言的访问创建副本)
假设你有一个函数:
void modify(int &x) {
x = 10; // 修改了引用变量 x
}
在 void modify(int &x)
中,x
是一个 int
类型的引用。这意味着:
引用的性质:x
并不是一个新的变量,而是直接引用了传入的整型变量。换句话说,x
是传入整型变量的别名。
改变引用的值:当你在 modify
函数中对 x
进行修改时,实际上是在修改传入的那个整型变量。因此,任何对 x
的改变都会直接影响到原始的变量。
如果你调用这个函数:
int a = 5;
modify(a); // a 现在变为 10
引用的语法更简洁,因为你不需要使用解引用操作符(*
)来访问引用的变量。
引用必须在定义时初始化,并且不能为 NULL
(或 nullptr
)。这意味着引用始终指向一个有效的对象,而指针可能指向 NULL
,从而引发潜在的空指针异常。
引用更像是对变量的别名,能够更清晰地表达意图。在许多情况下,使用引用的代码更易读,更容易理解。
在函数参数中使用引用,可以直接修改传入的变量,而不需要返回值。
L
的含义在代码中:
L
是整个链表的“入口”,也就是头指针。L
通常指向一个特殊的 头节点(dummy node)。头节点本身不存储实际的数据,只是为了方便操作整个链表,比如插入、删除和遍历等。L->next
指向链表的第一个有效节点(首元节点)。L->next == NULL
。e = p->data
的意义假设 p
当前指向第 i
个节点:
p->data
表示这个节点中存储的 数据部分。e = p->data
将该节点的数据部分赋值给变量 e
。为什么
p->data
可以访问数据?这是因为
p
是一个指向节点的指针,p->data
表示指针所指向节点的data
成员。
LNode *LocateElem(LinkList L, ElemType e)
LNode *
表示LocateElem函数返回的是一个指向链表节点的指针。
cin>>p->data;
>>
是 C++ 中的输入运算符。它是从标准输入(通常是键盘)中读取数据的方式之一。
>>
是 流提取运算符(stream extraction operator)。cin
是 C++ 的标准输入流对象,通常用于从键盘获取输入。