(第一章一一线性表)第二节线性表链式存储

说一下在链式存储中比较重要的一个概念,链式存储不仅需要存内容,还有其后继元素的地址。因此我们用一个节点Node来作为这两部分的组成数据的存储映像。存储数据元素的叫数据域,存储后继节点位置的叫指针域。
线性表的头,叫做头节点Head。头节点可以不存储任何信息,也可以存储线性表的长度等附加信息。但是必须要有指向第一个节点的指针域。(注意:头节点不算第一个节点。)

本小节主要讲的是对于单链表的操作:

  • 节点的创建
  • 链表的初始化
  • 链表的元素索引
  • 链表的删除
  • 头部插入和任意位置插入
  • 链表元素的输出
    通过类来实现,其中节点和链表都是类。代码如下:
// 单链表的操作
// Author: Thebluewinds
// Date: 2022.07.12
#include<iostream>
using namespace std;
#include<string>
#define MAXSIZE 20
#define error 0
#define ok 0

//线性表的节点
class Node
{
public:
	int data;
	Node* next; //用结构体指针来指向下一个节点。
};

//创建一个单链表类
class Linklist
{
public:
	Linklist(); //构造函数
	~Linklist(); // 析构函数
	void CreateList(int n);
	void CoutLinkList();
	int GetElem(int i);
	int Getlenth();
	void ListInsert(int i, int e);
	void ListDelete(); //删除指定位置元素
	void ListHeadInsert(int n); //在头部位置插入元素
private:
	Node* head; //头节点指针
};

//构造单链表初始化
Linklist::Linklist()
{
	head = new Node;
	head->data = 0;
	head->next = NULL;
}

//析构释放掉头节点
Linklist::~Linklist()
{
	delete head;
}

//创建一个单链表,长度为n
void Linklist::CreateList(int n)
{
	Node* p_new, *p_temp;
	p_temp = head; //当前节点,头指针
	if (n < 0) cout << "输入节点数有误。" << endl;
	for (int i = 0; i < n; i++)
	{
		p_new = new Node;  //新增的节点
		cout << "请输入第" << i + 1 << "个数值: ";
		cin >> p_new->data;
		p_new->next = NULL; //新节点装入数据,并指向空指针
		p_temp->next = p_new; //当前指针指向新的加入的节点
		p_temp = p_new;  // 新节点赋值给当前节点。
	}
}

//输出单链表的所有内容
void Linklist::CoutLinkList()
{
	//p指向L的第一个节点,head是头节点
	if (head == NULL || head->next == NULL) cout << "链表为空。" << endl;
	//新建一个节点指向head
	Node* p = head;
	while (p->next != NULL)
	{
		p = p->next; //第一次循环指向第一个节点。当前p为头节点
		cout << p->data << " ";
	}
	cout << endl;
}

//或许单链表的长度
int Linklist::Getlenth()
{
	int lenth=0;
	Node* p = head;
	while (p != NULL && p->next != NULL)
	{
		p = p->next;
		lenth++;
	}
	return lenth;
}

//单链表的读取,找到第i位的数据元素,并返回
int Linklist::GetElem(int i)
{
	int e;
	int j = 1;//计数器
	Node *p = head; //声明一个节点,然后让p指向头节点。
	//因为不知道单链表的长度,所以不能用for循环

	while (p->next !=NULL && j <= i)
	{
		p = p->next; //p指向下一个节点
		++j;
	}
	e = p->data;
	return e;
}

// 在i的位置上插入数据e
void Linklist::ListInsert(int i, int e)
{
	//1、声明一个节点p指向链表第一个节点,初始化从1开始
	//2、当j<i时,遍历链表,p指针向后移动,不断指向下一节点,j+1;
	//3、若链表为空,或者j超出i的范围,说明第i个元素不存在
	//4、否则查找成功,在系统中生成一个空的节点s。
	//5、将e赋值给s->data
	//6、单链表插入标准语句:s->next=p->next; p->next=s;
	//7、成功
	int j=1; //作为计数器
	if (i<1 || i>Getlenth()) cout << "位置错误。" << endl;
	Node* p = head;
	while (j < i)
	{
		p = p->next;
		j++;
	}
	//开辟一个新的节点用来存放插入的数值
	Node* p_temp = new Node;
	p_temp->data = e;
	p_temp->next = p->next; //让s指向p的后继节点
	p->next = p_temp;  // 让p指向s
}

void Linklist::ListDelete()
{
	int loc;
	int j = 1;
	if (head->next == NULL)
	{ 
		cout << "链表为空。" << endl;
	}
	else
	{ 
		cout << "请输入删除的元素: ";
		cin >> loc;
		if (loc<1 || loc>Getlenth()) cout << "输入位置错误" << endl;
		Node* p = head;
		while (loc > j)
		{
			p = p->next;
			j++;
		}
		Node *q = p->next; //p的下一下节点,也就是待删除的节点
		p->next = q->next; // p指向删除节点的后一个节点
		delete q;
		q = NULL;
	}
}

void Linklist::ListHeadInsert(int n)
{
	Node* p = head;
	Node* q = new Node;
	q->data = n;
	q->next = p->next;
	p->next = q;
}

int main() {
	Linklist list1;
	list1.CreateList(4); //创建单链表
	list1.CoutLinkList(); //输出链表数据
	int e = list1.GetElem(1); // 获取链表1位置上的数
	cout<<"lenth: "<<list1.Getlenth()<<endl; // 获取链表长度,并输出
	cout << "该位置上的数为:" << e << endl; 
	cout << "插入数据后:" << endl;
	list1.ListInsert(3, 99); // 在3位置上,插入99
	list1.CoutLinkList(); 
	cout << "删除指定位置数据后:" << endl;
	list1.ListDelete();
	list1.CoutLinkList();
	list1.ListHeadInsert(12);
	list1.CoutLinkList();
	system("pause");
	return 0;
}

这里提一下双向链表的内容。双向链表就是在单链表的每一个结点中,再设置一个指向其前驱结点的指针域。
定义的双向链表的类如下:

class Node
{
public:
	int data;
	Node* next;
	Node* prior;
};

双向链表对于求长度、查找元素、获取元素位置等和单链表都是几乎相同的。
下面说一个插入操作和删除操作,这两个是变动比较大的:

//双向链表插入结点p---s---p->next
s->prior = p;
s->next = p->next;
p->next->prior = s;
p->next = s;
delete p;
//双向链表的结点删除操作p->prior----p-----p->next
p->prior->next = p->next;
p->next->prior = p->prior;

好了,关于线性表的内容就先暂时看到这里,后续如果还有需要的会继续补充。然后总结一下线性表的主要知识点:

  1. 顺序存储结构
  2. 链式存储结构
    • 单链表
    • 静态链表
    • 循环链表
    • 双向链表
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值