单向链表演示C++

最简单的单项链表

\, \,这种单向链表中只有一个指向下一个节点的指针next,直接用链表节点类IntSLLNode来获取链表节点,手动将每一个节点的next指针连接到下一个节点

具体的操作步骤看注释就行

#pragma once
using namespace std;
class IntSLLNode
{
public:
	IntSLLNode();
	IntSLLNode(int i, IntSLLNode* in=nullptr)//重载的构造函数,构造本节点时,本节点的next指针为空
	{
		this->next = in;//本节点的next指针指向新建结点
		this->info = i;//初始化数据块
	}
	~IntSLLNode();

	int info;//链表结点的数据块
	IntSLLNode* next;//指向下一个节点的指针

private:

};

IntSLLNode::IntSLLNode()//默认构造函数
{
	next = nullptr;//默认构造出来的指针置空,安全性考虑
	info = 0;//数据块默认初始化为0
}

IntSLLNode::~IntSLLNode()
{
}

在使用该链表时,需要先产生一个指向IntSLLNode的指针p

就像这样:

#include"只有next的单向列表.h"
#include <iostream>
using namespace std;

int main()
{
    IntSLLNode* p;//链表的头
    p = new IntSLLNode(10);//另表头指向第一个数据为10的节点,并且这个10节点的next置空
    p->next = new IntSLLNode(8);//链接一个新节点8
    p->next->next = new IntSLLNode(50);//链接一个新节点50
    cout << "遍历链表" << endl;
    int i = 1;
    for (IntSLLNode* n =p; n != nullptr; n = n->next,i++)
    {
	cout << "第" << i << "个节点的数据为" << n->info << endl;
    }
}

一般的单向链表

这种链表除了有Node节点类还有一个List用来管理维护整个链表的所有节点

下面程序中设计了IntSLLNode类和IntSLList类来构建整个链表,IntSLList类相当于是整个链表的管家,其public部分中有维护整个链表的操作集

class IntSLLNode //链表节点
{
public:
	IntSLLNode();
	IntSLLNode(int i, IntSLLNode* otherNode = nullptr)//重载构造函数,用于生成节点
	{
		this->info = i;
		this->next = otherNode;
	}
	~IntSLLNode();

	int info;//数据块
	IntSLLNode* next;//指向下一个节点的指针


private:

};

IntSLLNode::IntSLLNode()//默认构造函数
{
	info = 0;
	next = nullptr;
}

IntSLLNode::~IntSLLNode()
{
}

我喜欢把IntSLList类称为这个链表的表头,在这个表头中还有两个IntSLLNode*指针,head和tail,用来指向整个链表的首尾结点,链表的大部分重要操作也是基于这两个指针完成的。 

class IntSLList
{
public:
	IntSLList();
	~IntSLList();

	//为该链表增加操作集
	int isEmpty()
	{
		return head == 0;
	}
	void addToHead(int);
	void addToTail(int);
	int deleteFromHead();//删除并且返回info
	int deleteFromTail();
	void deleteNode(int);
	bool isInList(int)const;

private:
	IntSLLNode* head, * tail;//与P不同的是,list表头设置了首尾指针
};

//IntSLList成员函数的实现
IntSLList::IntSLList()//list表头的默认构造函数,一个空list是没有node的
{
	head = tail = nullptr;
}

IntSLList::~IntSLList()//list的析构
{
	for (IntSLLNode* p=head; !isEmpty(); p = head->next)//遍历链表进行delete node操作
	{
		delete head;
		head = p->next;
	}
}

void IntSLList::addToHead(int el)
{
	head = new IntSLLNode(el,head);//申请的新节点的next指针被初始化成原来的head节点,同时将新节点的空间地址给list的head指针!!!
	if (tail == 0)//如果加入节点以前head=tail=nullptr,也就是空表,则把空的tail指针指向现在唯一的节点
	{
		tail = head;//list中只有唯一节点时,head与tail指向的是这个唯一节点
	}
}

void IntSLList::addToTail(int el)
{
	if (tail != nullptr)
	{
		tail->next = new IntSLLNode(el);//将新节点连接在原来尾节点的后面
		tail = tail->next;//将原来尾节点后移一位
	}
	else//此种情况对应空表
	{
		head = tail = new IntSLLNode(el);
	}
}

int IntSLList::deleteFromHead()
{
	//有两类情况要考虑
	//list中有节点
	int info;
	IntSLLNode* node;
	if (!isEmpty())
	{
		//再分两种情况
		if (head == tail)//唯一节点的情况
		{
			info = head->info;
			node = head;
			head = tail = nullptr;//删除后首尾指针置空
			delete node;
			return info;
		}
		else//多节点
		{
			info = head->info;
			node = head;
			head = head->next;//head节点后移即可
			delete node;
			return info;
		}
	}
	//list中没有节点
	else
	{
		cout << "空表,操作错误!" << endl;
		return 0;
	}
}

int IntSLList::deleteFromTail()
{
	int el = tail->info;
	IntSLLNode* temp = nullptr;
	if (head == tail)//唯一节点
	{
		delete head;
		head = tail = nullptr;
	}
	else//不唯一节点
	{
		for (temp = head; temp->next != tail; temp = temp->next);
		delete tail;
		tail = temp;
		tail->next = nullptr;//新尾部的next指针置空
	}
	return el;
}

void IntSLList::deleteNode(int el)
{
	if (head != nullptr)//如果list不空
	{
		if (head == tail && el == head->info)//唯一节点,且正好删除值等于节点的数据
		{
			delete head;
			head = tail = nullptr;
		}
		else if(el==head->info)//有多个节点,且头结点数据干好等于删除的值
		{
			IntSLLNode* temp = head;
			head = head->next;
			delete temp;
		}
		else//多个节点,遍历查找删除的值
		{
			IntSLLNode* temp,*prev;//由于是单项表,还需要设计一个prev指针来保存目标位置的前一个节点
			for (temp =head->next,prev=head
				; el != temp->info && temp != nullptr
				; temp = temp->next,prev=prev->next);//注意temp遍历到结尾的情况,此时temp=nullptr,说明list中没有目标值
			if (temp != nullptr)//目标值在表中
			{
				prev->next = temp->next;
				if (temp == tail)//如果删除的尾节点,则tail指针需要前移
					tail = prev;
				delete temp;
			}
		}
	}
	else
	{
		cout << "操作错误,空list" << endl;
	}
}

bool IntSLList::isInList(int el)const
{
	IntSLLNode* tmp;
	for (tmp = head; tmp != nullptr && tmp->info != el; tmp = tmp->next);
	return tmp != nullptr;
}

在设计链表增删操作的方法时,要注意增删位置在链表中的位置,就只有三种情况,head位置,tail位置和中间位置,不同位置对指针的连接方式会有不同,一般都要用if进行判断,这些在代码中已经解释的很详细了。除此之外,在首尾进行操作时,也要对节点数量进行判断,也有三种情况,最简单的情形是空链表,其次是单节点,再就是一般的多节点情形,针对不同的情形用if进行判断,并做好指针维护即可,这些在代码中也有详细的注释。

下面是简单的使用演示:

#include <iostream>
#include"普通单向链表.h"
using namespace std;

int main()
{
        IntSLList* list = new IntSLList;
	cout << "创建链表,检查状态:isEmpty()=" << list->isEmpty() << endl;
	cout << "开始添加节点,输入-999退出" << endl;
	int num;
	int i = 1;
	while (cin>>num)
	{
		if (num == -999)break;
		list->addToTail(num);
		cout << "(成功添加第" << i << "个节点)" << endl;
		i = i + 1;
	}
	cout << "添加完成" << endl;
	cout << "开始倒序弹出" << endl;
	while (!list->isEmpty())
	{
		cout << list->deleteFromTail();
	}
}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值