目录
双链表比单链表多了个指向前一个结点的指针,更方便进行插入和删除操作。
代码使用带头结点的链表,这样可以方便实现代码。
并且在初始化链表的时候使用尾插法建立链表。
双链表(C):
#include <stdio.h>
#include <stdlib.h>
typedef int ElemType;
typedef struct DNode { //双链表结点
ElemType data;
struct DNode* prior, * next;
}DNode,*DLinkList;
//默认采用带头结点、尾插法建立链表(方便写代码)
int DListInit(DLinkList* L)//此处的L为二级指针
{
int x;
*L = (DLinkList)malloc(sizeof(DNode)); //头结点
if (*L == NULL) return 0;
(*L)->prior = NULL;
(*L)->next = NULL;
DNode* r = *L;//尾指针
scanf_s("%d", &x);
while (x != 9999) {
DNode* s = (DNode*)malloc(sizeof(DNode));
if (s == NULL) return 0;
s->data = x;
r->next = s;
s->prior = r;
r = s; //尾插s,同时移动尾指针
scanf_s("%d", &x);
}
r->next = NULL;
return 1;
}
//链表判空
int DListIsEmpty(DLinkList L)
{
if (L->next == NULL)
return 1;
else
return 0;
}
//销毁链表
int DListDestory(DLinkList* L)
{
DNode* p = (*L)->next;//p指向待删除结点
while (p != NULL) {
(*L)->next = p->next;
p->next->prior = *L; //连接头结点与p的后一个结点
free(p);
p = (*L)->next;
}
p = *L;
free(p);
p = NULL;
*L = NULL; //删除头结点
return 1;
}
//查找第i个结点
DNode* DListSearchNode(DLinkList L, int i)
{
if (i < 1) return NULL;
DNode* p = L->next;//p初始指向第一个结点
int j = 1;//计数值
while (p != NULL && j < i) {
p = p->next;
j++;
}
return p;
}
//按值查找结点
DNode* DListSearchElem(DLinkList L, ElemType e)
{
DNode* p = L->next;//p初始指向第一个结点
while (p != NULL && p->data != e) {
p = p->next;
}
return p;
}
//求链表表长(头结点不算长度)
int DListLenth(DLinkList L)
{
if (L == NULL) return 0;
DNode* p = L->next;//p初始指向第一个结点
if (p == NULL) return 0;
int len = 1;
while (p->next != NULL) {
p = p->next;
len++;
}
return len;
}
//在p结点之后插入s结点
int InsertNextDNode(DNode* p, DNode* s)
{
if (p == NULL || s == NULL) return 0;
s->next = p->next;
if (p->next != NULL)
p->next->prior = s; //防止空指针出错
s->prior = p;
p->next = s;
return 1;
}
//在p结点之前插入s结点
int InsertPriorDNode(DNode* p, DNode* s)
{
if (p == NULL || s == NULL) return 0;
s->prior = p->prior;
p->prior->next = s;
s->next = p;
p->prior = s;
return 1;
}
//第i个位置后插结点e,新结点位于i处
int DListRearInsert(DLinkList* L, int i, ElemType e)
{
DNode* p = DListSearchNode(*L, i - 1);//找到第i-1个结点
if (p == NULL) return 0;
DNode* s = (DNode*)malloc(sizeof(DNode));
if (s == NULL) return 0;
s->data = e;
if (InsertNextDNode(p, s)) {//后插结点
return 1;
}
else {
return 0;
}
}
//第i个位置前插入结点e,新节点位于i-1处
int DListFrontInsert(DLinkList* L, int i, ElemType e)
{
DNode* p = DListSearchNode(*L, i - 1);//找到第i-1个结点
if (p == NULL) return 0;
DNode* s = (DNode*)malloc(sizeof(DNode));
if (s == NULL) return 0;
s->data = e;
if (InsertPriorDNode(p, s)) {//前插结点
return 1;
}
else {
return 0;
}
}
//删除第i个结点,并返回删除数据
int DListDeleteNode(DLinkList* L, int i, ElemType* e)
{
DNode* p = DListSearchNode(*L, i - 1);//找到第i-1个结点
if (p == NULL) return 0;
DNode* q = p->next;//q指向待删除结点
if (q == NULL) return 0;
p->next = q->next;
q->next->prior = p;
*e = q->data;
free(q);
q = NULL;
return 1;
}
//删除特定结点e
int DListDeleltNodeP(DLinkList* L, ElemType e)
{
DNode* p = DListSearchElem(*L, e);//p指向待删除结点
if (p == NULL) return 0;
if (p->next == NULL) { //表示p为链表最后一个结点
p->prior->next = NULL;
free(p);
p = NULL;
}
else {
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
p = NULL;
}
return 1;
}
//从头输出双链表
void DListPrint(DLinkList L)
{
if (L == NULL || L->next == NULL) return;
DNode* p = L->next;
int i = 1;
while (p != NULL) {
printf("data[%d]:%d ", i, p->data);
p = p->next; //必须先输出再移动指针
i++;
}
printf("\n");
}
int main()
{
DLinkList L;
/*************************链表初始化***************************/
printf("请输入数据,构建链表:\n");
DListInit(&L);
if (DListIsEmpty(L)) {
printf("链表为空!\n");
}
else {
printf("链表非空!\n");
}
printf("链表中数据为:\n");
DListPrint(L);
printf("链表长度为:%d\n", DListLenth(L));
/*************************************************************/
/*************************插入、删除结点***********************/
if (DListRearInsert(&L, 4, 12345)) {//在第4个位置后插入12345
printf("在第4个位置后插入12345成功!\n");
printf("链表中数据为:\n");
DListPrint(L);
printf("链表长度为:%d\n", DListLenth(L));
}
else {
printf("在第4个位置后插入12345失败!\n");
}
printf("\n\n");
if (DListFrontInsert(&L, 3, 999)) {//在第3个位置前插入999
printf("在第3个位置前插入999成功!\n");
printf("链表中数据为:\n");
DListPrint(L);
printf("链表长度为:%d\n", DListLenth(L));
}
else
{
printf("在第3个位置前插入999失败!\n");
}
printf("\n\n");
int e;
if (DListDeleteNode(&L, 5, &e)) {//删除第5个位置的结点
printf("删除第5个结点成功!删除的数据为:%d\n", e);
printf("链表中数据为:\n");
DListPrint(L);
printf("链表长度为:%d\n", DListLenth(L));
}
else {
printf("删除第5个结点失败!");
}
printf("\n\n");
/*************************************************************/
system("pause");
return 0;
}
双链表(C++):
#include <iostream>
typedef int ElemType;
typedef struct DNode { //双链表结点
ElemType data;
struct DNode* prior, * next;
}DNode, * DLinkList;
//默认采用带头结点、尾插法建立链表(方便写代码)
//C++可以使用引用,不需要操作二级指针;还可以使用bool来进行判断
bool DListInit(DLinkList& L)
{
int x;
L = (DLinkList)malloc(sizeof(DNode)); //头结点
if (L == NULL) return false;
L->prior = NULL;
L->next = NULL;
DNode* r = L;//尾指针
scanf_s("%d", &x);
while (x != 9999) {
DNode* s = (DNode*)malloc(sizeof(DNode));
if (s == NULL) return false;
s->data = x;
r->next = s;
s->prior = r;
r = s; //尾插s,同时移动尾指针
scanf_s("%d", &x);
}
r->next = NULL;
return true;
}
//链表判空
bool DListIsEmpty(DLinkList L)
{
if (L->next == NULL)
return true;
else
return false;
}
//销毁链表
bool DListDestory(DLinkList& L)
{
DNode* p = L->next;//p指向待删除结点
while (p != NULL) {
L->next = p->next;
p->next->prior = L; //连接头结点与p的后一个结点
free(p);
p = L->next;
}
p = L;
free(p);
p = NULL;
L = NULL; //删除头结点
return true;
}
//查找第i个结点
DNode* DListSearchNode(DLinkList L, int i)
{
if (i < 1) return NULL;
DNode* p = L->next;//p初始指向第一个结点
int j = 1;//计数值
while (p != NULL && j < i) {
p = p->next;
j++;
}
return p;
}
//按值查找结点
DNode* DListSearchElem(DLinkList L, ElemType e)
{
DNode* p = L->next;//p初始指向第一个结点
while (p != NULL && p->data != e) {
p = p->next;
}
return p;
}
//求链表表长(头结点不算长度)
int DListLenth(DLinkList L)
{
if (L == NULL) return false;
DNode* p = L->next;//p初始指向第一个结点
if (p == NULL) return false;
int len = 1;
while (p->next != NULL) {
p = p->next;
len++;
}
return len;
}
//在p结点之后插入s结点
bool InsertNextDNode(DNode* p, DNode* s)
{
if (p == NULL || s == NULL) return false;
s->next = p->next;
if (p->next != NULL)
p->next->prior = s; //防止空指针出错
s->prior = p;
p->next = s;
return true;
}
//在p结点之前插入s结点
bool InsertPriorDNode(DNode* p, DNode* s)
{
if (p == NULL || s == NULL) return false;
s->prior = p->prior;
p->prior->next = s;
s->next = p;
p->prior = s;
return true;
}
//第i个位置后插结点e,新结点位于i处
bool DListRearInsert(DLinkList& L, int i, ElemType e)
{
DNode* p = DListSearchNode(L, i - 1);//找到第i-1个结点
if (p == NULL) return false;
DNode* s = (DNode*)malloc(sizeof(DNode));
if (s == NULL) return false;
s->data = e;
if (InsertNextDNode(p, s)) {//后插结点
return true;
}
else {
return false;
}
}
//第i个位置前插入结点e,新节点位于i-1处
bool DListFrontInsert(DLinkList& L, int i, ElemType e)
{
DNode* p = DListSearchNode(L, i - 1);//找到第i-1个结点
if (p == NULL) return false;
DNode* s = (DNode*)malloc(sizeof(DNode));
if (s == NULL) return false;
s->data = e;
if (InsertPriorDNode(p, s)) {//前插结点
return true;
}
else {
return false;
}
}
//删除第i个结点,并返回删除数据
bool DListDeleteNode(DLinkList& L, int i, ElemType& e)
{
DNode* p = DListSearchNode(L, i - 1);//找到第i-1个结点
if (p == NULL) return false;
DNode* q = p->next;//q指向待删除结点
if (q == NULL) return false;
p->next = q->next;
q->next->prior = p;
e = q->data;
free(q);
q = NULL;
return true;
}
//删除特定结点e
bool DListDeleltNodeP(DLinkList& L, ElemType e)
{
DNode* p = DListSearchElem(L, e);//p指向待删除结点
if (p == NULL) return false;
if (p->next == NULL) { //表示p为链表最后一个结点
p->prior->next = NULL;
free(p);
p = NULL;
}
else {
p->prior->next = p->next;
p->next->prior = p->prior;
free(p);
p = NULL;
}
return true;
}
//从头输出双链表
void DListPrint(DLinkList L)
{
if (L == NULL || L->next == NULL) return;
DNode* p = L->next;
int i = 1;
while (p != NULL) {
printf("data[%d]:%d ", i, p->data);
p = p->next; //必须先输出再移动指针
i++;
}
printf("\n");
}
int main()
{
DLinkList L;
/*************************链表初始化***************************/
std::cout << "请输入数据,构建链表:\n";
DListInit(L);
if (DListIsEmpty(L)) {
std::cout << "链表为空!\n";
}
else {
std::cout << "链表非空!\n";
}
std::cout << "链表中数据为:\n";
DListPrint(L);
std::cout << "链表长度为:" << DListLenth(L) << std::endl;
/*************************************************************/
/*************************插入、删除结点***********************/
if (DListRearInsert(L, 4, 12345)) {//在第4个位置后插入12345
std::cout << "在第4个位置后插入12345成功!\n";
std::cout << "链表中数据为:\n";
DListPrint(L);
std::cout << "链表长度为:" << DListLenth(L) << std::endl;
}
else {
std::cout << "在第4个位置后插入12345失败!\n";
}
std::cout << "\n" << std::endl;
if (DListFrontInsert(L, 3, 999)) {//在第3个位置前插入999
std::cout << "在第3个位置前插入999成功!\n";
std::cout << "链表中数据为:\n";
DListPrint(L);
std::cout << "链表长度为:" << DListLenth(L) << std::endl;
}
else
{
std::cout << "在第3个位置前插入999失败!\n";
}
std::cout << "\n" << std::endl;
int e;
if (DListDeleteNode(L, 5, e)) {//删除第5个位置的结点
std::cout << "删除第5个结点成功!删除的数据为:" << e << std::endl;
std::cout << "链表中数据为:\n";
DListPrint(L);
std::cout << "链表长度为:" << DListLenth(L) << std::endl;
}
else {
std::cout << "删除第5个结点失败!\n";
}
std::cout << "\n" << std::endl;
/*************************************************************/
system("pause");
return 0;
}
测试结果:
总结:
双链表插入以及删除的时候要小心操作指针,防止发生空指针错误、指向不正确等问题。
以上
以上均为个人学习心得,如有错误,请不吝赐教~
THE END