版权声明:@Keanu https://blog.csdn.net/weixin_41174072/article/details/83213483
这次是系列二,双链表,具体的说明就不太详细说了,注释都加到Code中去了,很详细,特此记录~
还是先简单说一下双链表:
以下是维基百科中对双链表的定义:
双向链表,又称为双链表,是链表的一种,它的每个数据结点中都有两个指针,分别指向直接后继和直接前驱。所以,从双向链表中的任意一个结点开始,都可以很方便地访问它的前驱结点和后继结点。一般我们都构造双向循环链表。
再看直观图:
其实循环双链表只是将一个链变成了一个环,他们都可以从任意一个位置开始,访问链上的任意一个元素,循环链表的尾节点的next指针指向了头结点,而头节点的prior指针则是指向了尾节点.
接下来就是双链表的一些基本功能,而循环列表就需要进一步的拓展了,这里不再赘述:
首先是DLinkList.h:
#include <stdio.h>
#include <malloc.h>
#ifndef DLNODE_DLINKLIST_H
#define DLNODE_DLINKLIST_H
#define TRUE 1
#define ERROR 0
//双链表
typedef struct DLNode {
int data;
struct DLNode *prior;
struct DLNode *next;
} DLinkList;
/**
* 头插法建立双链表
* @param L 双链表
* @param a 链表元素
* @param n 链表长度
* @return 返回的是生成的链表的首节点的地址
*/
DLinkList * CreateListByHead(DLinkList *L, int a[], int n) {
DLinkList *s;
L->prior = L->next = NULL;
for (int i = 0; i < n; ++i) {
s = (DLinkList *) malloc(sizeof(DLinkList));
s->data = a[i];
s->next = L->next;
if (L->next != NULL)
L->next->prior = s;
L->next = s;
s->prior = L;
}
return L;
}
/**
* 尾插法建立双链表
* @param L 双链表
* @param a 链表元素
* @param n 链表长度
* @return 返回的是生成的链表的首节点的地址
*/
DLinkList * CreateListByRoil(DLinkList *L, int a[], int n) {
DLinkList *r = L, *s; //r指针用来指向L的尾节点,s 是每次产生的新的节点
for (int i = 0; i < n; ++i) {
s = (DLinkList *) malloc(sizeof(DLinkList));
s->data = a[i];
r->next = s;
s->prior = r;
r = s;//r始终指向链表的尾节点
}
r->next = NULL;
return L;
}
/**
* 在双链表某逻辑位置上插入值为e的元素
* @param L 传入的双链表
* @param i 逻辑位置
* @param e 插入的元素
* @return 插入成功返回TRUE(1),失败返回ERROR(0)
*/
int ListInsert(DLinkList *L, int i, int e) {
DLinkList *r = L, *s;
int j = 0;
while (r != NULL && j < i - 1) {//找到第i-1个位置
j++;
r = r->next;
}
if (r == NULL)
return ERROR;
else {
s = (DLinkList *) malloc(sizeof(DLinkList));
s->data = e;
s->next = r->next;
//可能在最后一个节点之后插入,此时最后一个节点的next为NULL,不包含指针
if (r->next != NULL)
r->next->prior = s;
r->next = s;
s->prior = r;
return TRUE;
}
}
/**
* 删除双链表上逻辑位置的元素
* @param L 双链表
* @param i 逻辑位置
* @return 成功返回TRUE(1),失败返回ERROR(0)
*/
int ListDelete(DLinkList *L, int i) {
DLinkList *p = L, *q;
int j = 0;
//首先找到逻辑位置第i-1个元素,防止指针断链
//跟下标没有关系,因为j<i最后出来的是移动次数
while (p != NULL && j < i - 1) {
j++;
p = p->next;
}
if (p == NULL)
return ERROR;
else {
q = p->next;
//删除位置为空
if (q == NULL) {
return ERROR;
}
p->next = q->next;
//这里其实要分成两种情况,但是最后提取了一下代码
//可能删除的是最后一个节点
if (q->next != NULL)
q->next->prior = p;
free(q);
return TRUE;
}
}
/**
* 输出双链表
*/
void OutputLink(DLinkList *L){
//输出前i-1个元素
while (L->next != NULL){
printf("%d<=>",L->data);
L = L->next;
}
printf("%d",L->data);
}
#endif //DLNODE_DLINKLIST_H
main函数:
#include <stdio.h>
#include "DLinkList.h"
#define MAX_SIZE 5
int main() {
DLinkList *L = (DLinkList *) malloc(sizeof(DLinkList));
int a[MAX_SIZE];
for (int i = 0; i < MAX_SIZE; ++i) {
a[i] = i+1;
}
//头插法创建双链表
printf("\n头插法建立的双链表为: ");
OutputLink(CreateListByHead(L, a, MAX_SIZE));
//尾插法创建双链表
printf("\n尾插法建立的双链表为: ");
OutputLink(CreateListByRoil(L, a, MAX_SIZE));
//在特定位置插入(注意,此时的L为尾插法建立的链表)
int k = ListInsert(L, 6, 9);
if (k == 0)
printf("\nERROR!");
else
printf("\n在第六个位置插入后的双链表为: "); OutputLink(L);
//删除特定位置元素(注意,此时的L为尾插法建立的链表)
int z = ListDelete(L, 6);
if (z == 0)
printf("\nERROR!");
else
printf("\n删除第六个位置的元素后的双链表为: ");OutputLink(L);
return 0;
}