链式表是一种常见的数据结构,它通过节点和指针的方式实现元素的存储和连接。
链式表由一系列节点组成,每个节点包含一个数据元素和一个指向下一个节点的指针。通过节点之间的指针链接,形成一个链式结构,从而实现元素的顺序存储和访问。
相比于顺序表(使用数组实现的线性表),链式表的插入和删除操作更加高效,因为它只需要修改相邻节点的指针,不需要进行元素的移动。但是查找元素的操作相对较慢,需要从头节点开始遍历链表,直到找到目标元素或者到达链表末尾。
链式表常见的类型有单链表、双向链表和循环链表。
-
单链表:每个节点只包含一个指针,指向下一个节点。链表的头指针指向链表的第一个节点,尾节点的指针为NULL,表示链表的结束。
-
双向链表:每个节点除了包含指向下一个节点的指针,还包含指向前一个节点的指针。双向链表可以实现前向和后向的遍历。
-
循环链表:尾节点的指针指向头节点,形成一个环状结构。循环链表可以实现循环遍历。
链式表的常见操作包括:
- 插入:在指定位置插入一个新节点。
- 删除:删除指定位置的节点。
- 查找:根据元素的值或者位置,查找对应的节点。
- 修改:修改指定位置的节点的值。
- 遍历:依次访问链表中的每个节点。
链式表的应用广泛,能够灵活地处理动态数据结构的问题。它在各种算法和程序设计中都有重要的应用,例如实现栈、队列、图等数据结构和算法。
-
定义了头结点类型以及双向链表节点的结构体
DuLNode
,并使用typedef
进行类型别名定义。DuLNode
结构体包含数据域data
,以及指向前驱节点和后继节点的指针域prior
和next
。 -
LinkListInit
函数用于初始化双向链表,创建一个空的双向链表,通过L
参数返回链表头结点的指针。 -
GetElem_L
函数在带头结点的双向链表L
中查找第i
个结点,并返回该结点的指针。这个函数通过遍历链表,依次移动到指定位置来实现查找。 -
ListInsert_L
函数在双向链表L
的第i
个位置之前插入新的元素x
。首先使用GetElem_L
函数找到位置为i-1
的节点,然后创建新的节点s
,将s
插入到i
位置并调整前驱和后继节点的指针指向。 -
ListDelete_L
函数用于删除双向链表L
中的第i
个节点。通过GetElem_L
找到位置为i-1
的节点p
,然后将p
指向的节点q
的前驱节点的next
指针指向q
的后继节点,将q
的后继节点的prior
指针指向p
的前驱节点,最后释放节点q
的空间。 -
CreateList_L
函数用于逆序输入n
个数据元素,创建带头结点的双向链表。首先调用LinkListInit
初始化链表,然后使用循环逐个创建节点并插入到链表头部。 -
DispList_L
函数用于输出双向链表的所有元素值。通过遍历链表,依次输出每个节点的数据域。 -
在
main
函数中,创建双向链表L
并调用CreateList_L
进行初始化。然后分别调用DispList_L
输出链表元素。接着使用ListInsert_L
在链表第6
个位置插入元素10
,并调用DispList_L
输出链表。最后使用ListDelete_L
删除链表第6
个位置的节点,并再次调用DispList_L
输出链表。
总体来说,这段代码实现了双向链表的基本操作,包括初始化、插入、删除、遍历等。可以通过调用这些函数来对双向链表进行操作。需要注意的是,代码中存在一些潜在的问题,比如没有进行错误处理和内存释放。在实际应用中需要主动处理这些问题。
这段代码是一个实现双向链表的程序。下面是代码的分析:
- 定义了双向链表节点的数据结构:
typedef struct DuLNode {
ElemType data; // 数据域
struct DuLNode *prior; //指向前驱的指针域
struct DuLNode *next; //指向后继的指针域
} DuLNode, *DuLinkList;
- 初始化双向链表:
void LinkListInit(DuLinkList &L) {
L = new DuLNode; // 创建头结点
if (!L) exit(OVERFLOW);
L->next = L->prior = NULL; // 初始化指针域
}
- 在双向链表中查找第i个节点:
DuLNode *GetElem_L(DuLinkList L, int i) {
DuLNode *p;
p = L->next;
int j = 1; // 计数器
while (p != L && j < i) { // 顺指针向后查找,直到p指向第i个元素或p为空
p = p->next;
++j;
}
if (j == i) return p; // 第i个元素存在
else return NULL; // 第i个元素不存在
}
- 在双向链表的第i个位置之前插入元素x:
int ListInsert_L(DuLinkList &L, int i, ElemType x) {
DuLNode *p, *s;
p = GetElem_L(L, i - 1);
if (!p) return ERROR;
s = new DuLNode; // 生成新结点
s->data = x;
if (p->next) {
p->next->prior = s;
s->next = p->next;
s->next->prior = p;
p->next = s;
} else { //插入在L尾部的处理
s->next = p->next;
p->next = s;
s->prior = p;
}
return OK;
}
- 删除双向链表中的第i个节点:
int ListDelete_L(DuLinkList &L, int i) {
DuLNode *p, *q;
p = GetElem_L(L, i - 1);
if (!p) return ERROR; //删除位置不合理
if (p->next->next) {
q = p->next;
q->next->prior = p;
p->next = q->next; //删除并释放结点
} else { //删除尾部结点
q = p->next;
p->next = NULL;
q->prior = NULL;
}
delete q;
return OK;
}
- 创建双向链表:
void CreateList_L(DuLinkList &L, int n) {
DuLNode *p;
LinkListInit(L); //建立空表
for (int i = n; i > 0; --i) {
p = new DuLNode; //新增结点
scanf("%d", &p->data); //输入元素值
p->next = L->next;
p->prior = L;
L->next = p;
}
}
- 输出双向链表中的元素:
void DispList_L(DuLinkList L) {
DuLNode *p;
for (p = L->next; p; p = p->next) printf("%d ", p->data);
printf("\n");
}
- 主函数:
int main() {
DuLinkList L;
DuLNode *p;
CreateList_L(L, 5);
DispList_L(L);
ListInsert_L(L, 6, 10);
DispList_L(L);
ListDelete_L(L, 6);
DispList_L(L);
return 0;
}
主函数中演示了创建一个双向链表,插入元素和删除元素。在输出结果时,双向链表的元素将会逐个打印到控制台。
完整代码
双向链表
# include <stdlib.h>
# include <stdio.h>
# define OK 1
# define OVERFLOW -1
# define ERROR 0
typedef int ElemType;/
typedef struct DuLNode {
ElemType data; // 数据域
struct DuLNode *prior; //指向前驱的指针域
struct DuLNode *next; //指向后继的指针域
}DuLNode,*DuLinkList;
void LinkListInit(DuLinkList &L){
L=new DuLNode;
if(!L)exit(OVERFLOW);
L->next=L->prior=NULL;
}
DuLNode *GetElem_L(DuLinkList L,int i){//在带头结点的双向链表L中查找第i个结点,找到返回该结点,否则返回空
DuLNode *p;
p=L->next;
int j=1; //p指向第一个结点,j为计数器
while(p!=L&&j<i){p=p->next; ++j;} //顺指针向后查找,直到p指向第i个元素或p为空
if(j==i)return p; //第i个元素存在
else return NULL; //第i个元素不存在
}
int ListInsert_L(DuLinkList &L,int i,ElemType x){//在双向链表L中第i个位置之前插入元素x
DuLNode *p,*s;
p=GetElem_L(L,i-1);
if(!p)return ERROR;
s=new DuLNode; //生成新结点
s->data=x;
if(p->next){
p->next->prior=s;
s->next=p->next;
s->next->prior=p;
p->next=s;
}
else{//插入在L尾部的处理
s->next=p->next;
p->next=s;
s->prior=p;
}
return OK;
}
int ListDelete_L(DuLinkList &L,int i){
DuLNode *p,*q;
p=GetElem_L(L,i-1);
if(!p)return ERROR; //删除位置不合理
if(p->next->next){
q=p->next;
q->next->prior=p;
p->next=q->next; //删除并释放结点
}
else{//删除尾部结点
q=p->next;
p->next=NULL;
q->prior=NULL;
}
delete q;
return OK;
}
void CreateList_L(DuLinkList &L,int n) {//逆序输入n个数据元素,建立带头结点的双向链表
DuLNode *p;
LinkListInit(L); //建立空表
for(int i=n; i>0; --i){
p=new DuLNode;//新增结点
scanf("%d",&p->data); //输入元素值
p->next=L->next;
p->prior=L;
L->next=p;
}
}
void DispList_L(DuLinkList L) {
DuLNode *p;
for(p=L->next;p;p=p->next)printf("%d ",p->data);
printf("\n");
}
//void CreateList_L(DuLinkList &L,int n){
// DuLNode *p,*r;
// LinkListInit(L); //建立空表
// r=L; //r始终指向表尾结点
// for(int i=1; i<=n; i++){
// p=new DuLNode;
// scanf("%d",&p->data); //输入元素值
// r->next=p; //插入到表尾
// r=p;
// }
// r->next=NULL;
//}
int main(){
DuLinkList L;
DuLNode *p;
CreateList_L(L,5);
DispList_L(L);
// p=GetElem_L(L,3);
// if(p!=NULL)printf("%d\n",p->data);
ListInsert_L(L,6,10);
DispList_L(L);
ListDelete_L(L,6);
DispList_L(L);
return 0;
}