简单一文带你了解链表结构--附完整代码

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


链表

相信很多友友们在学习链表的时候会有一点点小疑惑吧,那么看这篇文章就可以一解烦恼


提示:以下是本篇文章正文内容,下面案例可供参考

一、链表结构

平时不怎么画图所以略显难看,但斯是图陋,内容则精
平时不怎么画图所以图片略显简陋点

struct node {
	int data;
	node* next;
	node() :next(NULL) {};
};
链表由一个又一个结点构成,每个结点都有一个数据域(data)和指针域(next)结点之间就是通过指针域相连接。
通常来说链表第一个结点称之为头结点,由头指针指向它,并且头结点不存储数据也就是数据域data为空,规范书写代码所以在构造函数里用初始化列表将next指针设为空指针

二、链表

1.单向链表

话不多说,上代码清晰了然

#include <iostream>
using namespace std;
struct node {
	int data;
	node* next;
	node() :next(NULL) {};
};

//遍历链表
node* traverse(node* h)
{
	if (h == NULL)
	{
		cout << "链表为空" << endl;
		return NULL;

    }
	h = h->next;
	while (h->next != NULL)
	{
		cout << h->data;
		h = h->next;
	}
	return NULL;
}
//查找数据
node* search(node* h, int x)
{
	if (h ==NULL)
	{
		cout << "空链表查找失败" << endl;
		return NULL;
	}
	while (h->next != NULL)
	{
		h = h->next;
		if (h->data == x)
		{
			cout << "找到此节点了" << endl;//这里最好是可以给每个节点加一个编号
			return h;
		}

	}
	return NULL;

}
//增加一个新节点
void addnode(node* p, int x)
{
	
	node* q = new node;
	if (q == NULL)
	{
		cout << "堆区内存溢出,创建失败" << endl;//在正式代码书写中一定要判断节点到底有没有创建成功,一旦内存溢出就g了
		return;
	}
	p->data = x;
	q->next = p->next;
	p->next = q;
}
//创建链表这里就会用到二级指针了,当然也可以一级指针加引用
void create_node(node** phead, int a[], int n)//这里用一个数组来分配数据域,n是元素个数
{
	if (*phead == NULL)
	{
		*phead = new node;

    }
	for (int i = 0; i < n; i++)
	{
		addnode(*phead, a[i]);
	}

}
//做删除操作,删除p的直接后继
void delnode(node* p)
{
	if (p = NULL)return;
	node * q = p->next;
	if (q = NULL)return;
	p->next = q->next;
	delete q;
	q = NULL;
	



}

上面代码基本已经是最简化的样子了,是很好理解的就不多赘叙了,有一个小注意点还是要说下的,就是在创建一个新结点时都要判断下是否创建成功,不然等堆区内存溢出程序报错的时候根本看不明白是哪里出来问题
(经验告诉我这一个小举措用处非常大的)
在这里插入图片描述

2.双向链表

在这里插入图片描述
还是这个图在这里插入图片描述
相比单链表,双向链表多了一个指针域(前继链域)除此之外基本没差
上代码

代码如下(示例):

#include<iostream>
using namespace std;
const int n = 5;
int a[n];
struct node
{
	int data;
	node* pre;
	node* next;
	node() :pre(NULL), next(NULL) {};//初始化指针域

};
void nexinsert(node* p, int x)//在p后面插入一个节点
{
	node* q = new node;
	if (q == NULL)
	{
		cout << "堆区内存溢出,插入失败" << endl;
		return;
	}
	if(p->next!=NULL)
	{
	q->data = x;
	q->next = p->next;
	p->next->pre = q;
	p->next = q;
	q->pre = p;}
	else
	{
		p->next = q;
		q->pre = p;

	}

}
void preinsert(node*&p, int x)
{
	node* q = new node;
	node* pre = p->pre;
	if (q == NULL)
	{
		cout << "堆区内存溢出,插入失败" << endl;
		return;
	}//这块都是一样的,很多人嫌麻烦就省去了,等报错的时候都不懂报错的原因是什么
	q->data = x;
	q->next = p;
	p->pre = q;
	if (p->pre != NULL)
	{
		q->pre = pre;
		pre->next = q;
	}
	else
	{
		p = q;//当p是表头的时候将头指针往前移动指向q

	}




}
void create_node(node** p)//创建双向链表
{
	*p = new node;
	for (int i = 0; i < n; i++)
	{
		nexinsert(*p, a[i]);
	}
}


3.循环链表

循环链表和单链表只多了一个最后结点的next指向头结点,但是在循环链表中大多称呼最后一个结点为头结点
在这里插入图片描述

总结

链表基础部分就这些了,还有个双向循环链表跟上面几乎都是一样的,所以就没写了。
代码很基础,也很好理解希望各位友友们点个赞跟关注()

有任何问题都可以评论区提出也可以私信发我,代码如有错误也希望指出!

  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值