【链表】还不会用C++实现链表?一文教会你各种链表的实现

本文将用C++语言来实现数据结构中的无头单链表,带头循环链表,以及带头循环双向链表等链表结构(带头单链表与后两种链表的结构相似,实现起来比后两种更简单,读者阅读完本文即可自行实现)

【链表】还不会用C++实现链表?一文教会你各种链表的实现_第1张图片

一、无头单链表的实现

无头单链表在头插时需要改变头指针的位置,具体代码实现如下:

//无头单链表

#include 
#include 

using namespace std;

template 

//先定义链表中的节点
struct SListNode
{
	T data;
	SListNode* next;

	SListNode(T x)
	{
		this->data = x;
		this->next = nullptr;
	}
};

template 
class SList
{
private:
	//链表初始化后链表中就有一个节点
	SListNode* head;
	
public:
	SList(T x)
	{
		this->head = new SListNode(x);
	}

	~SList()
	{
		SListNode* cur = head;
		while (cur)
		{
			SListNode* next = cur->next;
			delete cur;
			cur = next;
		}
	}


	// 动态申请一个节点
	SListNode* BuySListNode(T x);

	// 单链表打印
	void SListPrint();

	// 单链表尾插
	void SListPushBack(T x);

	// 单链表的头插
	void SListPushFront(T x);

	// 单链表的尾删
	void SListPopBack();

	// 单链表头删
	void SListPopFront();

	// 单链表查找
	SListNode* SListFind(T x);

	// 单链表在pos位置之后插入x
	void SListInsertAfter(SListNode* pos, T x);

	// 单链表删除pos位置之后的值
	void SListEraseAfter(SListNode* pos);

};


template 
SListNode* SList:: BuySListNode(T x)
{
	SListNode* tmp = new SListNode(x);
	tmp->next = nullptr;
	return tmp;
}

template 
void SList::SListPrint()
{
	SListNode* cur =head;
	while (cur)
	{
		cout << cur->data << "->";
		cur = cur->next;
	}
	cout << "NULL" << endl;
}

template 
void SList::SListPushBack(T x)
{
	SListNode* cur = head;

	while (cur->next)
	{
		cur = cur->next;
	}
	SListNode* newnode = BuySListNode(x);
	cur->next = newnode;//连接
}
template 
void SList::SListPushFront(T x)
{
	SListNode* newnode = BuySListNode(x);
	newnode->next = head;
	head = newnode;
}

template 
void SList::SListPopBack()
{
	assert(head);//头结点为空就不能继续删除了
	SListNode* tail = head;
	//链表中只有一个节点就只能删除头结点
	if (tail->next == nullptr)
	{
		delete head;
	}
	else
	{
		while (tail->next->next != NULL)
		{
			tail = tail->next;
		}
		delete tail->next;
		tail->next = nullptr;
	}

}

template 
void SList::SListPopFront()
{
	assert(head);
	SListNode* cur = head->next;
	delete head;
	head = cur;
}

template 
SListNode* SList::SListFind(T x)
{
	assert(head);
	SListNode* cur = head;
	while (cur)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return nullptr;
}

template 
void SList::SListInsertAfter(SListNode* pos, T x)
{
	assert(pos);
	SListNode* newnode = BuySListNode(x);
	newnode->next = pos->next;
	pos->next = newnode;
}


template 
void SList::SListEraseAfter(SListNode* pos)
{
	assert(pos->next && pos);
	SListNode* cur = pos->next;
	pos->next = pos->next->next;
	delete cur;
}


int main()
{

	SList cur(1);

	cur.SListPushBack(2);
	cur.SListPushBack(3);
	cur.SListPushBack(4);
	cur.SListPushBack(5);
	cur.SListPushBack(6);
	cur.SListPrint();

	cur.SListPopFront();
	cur.SListPrint();

	cur.SListPopBack();
	cur.SListPrint();

	SListNode* p1 = cur.SListFind(2);
	cur.SListInsertAfter(p1, 20);
	cur.SListPrint();

	cur.SListEraseAfter(p1);
	cur.SListPrint();


	
	return 0;
}

二、带头循环链表的实现

带头意味着链表中会一直存在着一个头结点,无论链表的插入还是删除都是对头结点后面的节点进行的操作。头插的节点也是直接连接在头结点的下一个结点,不会改变头结点。循环意味着尾节点的next指针指向头节点,就像是形成了一个环一样。

具体实现代码如下:

#include 
#include 

using namespace std;

template 
struct Node
{
	T data;
	struct Node* next;
	Node()
	{
		this->data = 0;
		this->next = nullptr;
	}
	Node(T data)
	{
		this->data = data;
		this->next = nullptr;
	}
};

template 
class SList
{
private:
	Node* head;
	Node* tail;
public:
	SList()
	{
		this->head = new Node();
		this->tail = head;
	}

	~SList()
	{
		Node* p = head;
		Node* q = head;
		while (p != tail)
		{
			q = p->next;
			delete p;
			p = q;
		}
		delete tail;
	}

	
	// 动态申请一个节点
	Node* BuySListNode(T x);

	// 单链表打印
	void SListPrint();

	// 单链表尾插
	void SListPushBack(T x);

	// 单链表的头插
	void SListPushFront(T x);

	// 单链表的尾删
	void SListPopBack();

	// 单链表头删
	void SListPopFront();

	// 单链表查找
	Node* SListFind( T x);

	// 单链表在pos位置之后插入x
	void SListInsertAfter(Node* pos, T x);

	// 单链表删除pos位置之后的值
	void SListEraseAfter(Node* pos);

};

template 
Node* SList::BuySListNode(T x)
{
	Node* tmp = new Node;
	tmp->data = x;
	tmp->next = nullptr;
	return tmp;
}

template 
void SList::SListPrint()
{
	assert(head->next);//保证头节点后还有结点才打印,不然报错
	Node* cur = head->next;
	while (cur != head)
	{
		cout << cur->data << "->";
		cur = cur->next;
	}
	cout << "NULL" << endl;
}

template 
void SList::SListPushBack(T x)
{
	Node* newnode = BuySListNode(x);
	tail->next = newnode;
	tail = newnode;
	tail->next = head;//尾节点的next指向头节点
}

template 
void SList::SListPushFront(T x)
{
	Node* newnode = BuySListNode(x);
	if (head == tail)
	{
		head->next = newnode;
		tail = newnode;
		tail->next = head;
	}
	else
	{
		newnode->next = head->next;
		head->next = newnode;
	}
}

template 
void SList::SListPopBack()
{
	assert(head->next);
	Node* cur = head;
	while (cur->next != tail)
	{
		cur = cur->next;
	}
	delete tail;
	tail = cur;
	tail->next = head;

}

template 
void SList::SListPopFront()
{
	assert(head->next);
	Node* cur = head->next;

	if (head->next == tail)
	{
		delete tail;
		tail = head;
	}
	else
	{
		head->next = cur->next;
		delete cur;
	}
}

template 
Node* SList::SListFind(T x)
{
	assert(head->next);
	Node* cur = head->next;
	while (cur != head)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return nullptr;
}

template 
void SList::SListInsertAfter(Node* pos, T x)
{
	assert(pos);
	if (pos->next == head)
	{
		SListPushBack(x);
	}
	else if(pos == head)
	{
		SListPushFront(x);
	}
	else
	{
		Node* newnode = BuySListNode(x);
		newnode->next = pos->next;
		pos->next = newnode;
	}
}
template 
void SList::SListEraseAfter(Node* pos)
{
	assert(pos);
	//尾节点后的头节点不能删
	if (pos->next == head)
	{
		exit(-1);
	}
	else if (pos == head)
	{
		SListPopFront();
	}
	else
	{
		Node* cur = pos->next;
		pos->next = pos->next->next;
		delete cur;
	}
}


int main()
{

	SList SL1;
	SL1.SListPushBack(1);
	SL1.SListPushBack(2);
	SL1.SListPushBack(3);
	SL1.SListPushBack(4);
	SL1.SListPushBack(5);
	SL1.SListPrint();

	SL1.SListPushFront(10);
	SL1.SListPrint();

	SL1.SListPopFront();
	SL1.SListPrint();

	SL1.SListPopBack();
	SL1.SListPrint();

	Node* cur = SL1.SListFind(2);
	SL1.SListInsertAfter(cur, 20);
	SL1.SListPrint();

	SL1.SListEraseAfter(cur);
	SL1.SListPrint();

	return 0;
}

三、带头双向循环链表的实现

具体实现思路与带头循环链表大同小异,只是在节点中需要增加一个指向前一个节点的指针。

具体实现代码如下:

#include 
#include 

using namespace std;

template 
struct Node
{
	T data;
	struct Node* prev;//指向前一个节点的指针
	struct Node* next;
	Node()
	{
		this->data = 0;
		this->prev = nullptr;
		this->next = nullptr;
	}
	Node(T data)
	{
		this->data = data;
		this->prev = nullptr;
		this->next = nullptr;
	}
};

template 
class SList
{
private:
	Node* head;//头节点
	Node* tail;//尾节点
public:
	SList()
	{
		this->head = new Node();
		head->next = nullptr;
		head->prev = nullptr;
		this->tail = head;
	}

	~SList()
	{
		Node* p = head;
		Node* q = head;
		while (p != tail)
		{
			q = p->next;
			delete p;
			p = q;
		}
		delete tail;
	}

	Node* getHead()
	{
		return this->head;
	}

	// 动态申请一个节点
	Node* BuySListNode(T x);

	// 单链表打印
	void SListPrint();

	// 单链表尾插
	void SListPushBack(T x);

	// 单链表的头插
	void SListPushFront(T x);

	// 单链表的尾删
	void SListPopBack();

	// 单链表头删
	void SListPopFront();

	// 单链表查找
	Node* SListFind(T x);

	// 单链表在pos位置之后插入x
	void SListInsertAfter(Node* pos, T x);

	// 单链表删除pos位置之后的值
	void SListEraseAfter(Node* pos);

};

template 
Node* SList::BuySListNode(T x)
{
	Node* tmp = new Node;
	tmp->data = x;
	tmp->prev = nullptr;
	tmp->next = nullptr;
	return tmp;
}

template 
void SList::SListPrint()
{
	assert(head->next);
	Node* cur = head->next;
	while (cur != head)
	{
		cout << cur->data << "<->";
		cur = cur->next;
	}
	cout << endl;
}

template 
void SList::SListPushBack(T x)
{
	Node* newnode = BuySListNode(x);
	tail->next = newnode;
	newnode->prev = tail;
	tail = newnode;
	tail->next = head;
	head->prev = tail;
}

template 
void SList::SListPushFront(T x)
{
	Node* newnode = BuySListNode(x);
	if (head == tail)//头节点后没有节点
	{
		head->next = newnode;
		newnode->prev = head;
		tail = newnode;
		tail->next = head;
		head->prev = tail;
	}
	else
	{
		newnode->next = head->next;
		newnode->prev = head;
		head->next = newnode;
	}
}

template 
void SList::SListPopBack()
{
	assert(head->next);

	Node* cur = tail->prev;
	head->prev = tail->prev;
	delete tail;
	tail = cur;
	tail->next = head;
	
}


template 
void SList::SListPopFront()
{
	assert(head->next);//只剩头节点不删
	Node* cur = head->next;

	if (head->next == tail)//头节点后只有一个节点
	{
		delete tail;
		tail = head;
		head->next = head;
		head->prev = head;
	}
	else
	{
		head->next = cur->next;
		cur->next->prev = head;
		delete cur;
	}
}

template 
Node* SList::SListFind(T x)
{
	assert(head->next);
	Node* cur = head->next;
	while (cur != head)
	{
		if (cur->data == x)
		{
			return cur;
		}
		cur = cur->next;
	}
	return nullptr;
}

template 
void SList::SListInsertAfter(Node* pos, T x)
{
	assert(pos);
	if (pos->next == head)
	{
		SListPushBack(x);
	}
	else if (pos == head)
	{
		SListPushFront(x);
	}
	else
	{
		Node* newnode = BuySListNode(x);
		newnode->next = pos->next;
		newnode->prev = pos;
		pos->next = newnode;
	}
}


template 
void SList::SListEraseAfter(Node* pos)
{
	assert(pos);
	if (pos->next == head)//尾节点后的头节点不删
	{
		exit(-1);
	}
	else if (pos == head)
	{
		SListPopFront();
	}
	else
	{
		Node* cur = pos->next;
		pos->next = pos->next->next;
		pos->next->prev = pos;
		delete cur;
	}
}


int main()
{
	//SListNode* head = new SListNode;

	SList SL1;
	SL1.SListPushBack(1);
	SL1.SListPushBack(2);
	SL1.SListPushBack(3);
	SL1.SListPushBack(4);
	SL1.SListPushBack(5);
	SL1.SListPrint();

	SL1.SListPushFront(10);
	SL1.SListPrint();

	SL1.SListPopFront();
	SL1.SListPrint();

	SL1.SListPopBack();
	SL1.SListPrint();

	Node* cur = SL1.SListFind(2);
	SL1.SListInsertAfter(cur, 20);
	SL1.SListPrint();

	SL1.SListEraseAfter(cur);
	SL1.SListPrint();

	return 0;
}

你可能感兴趣的:(链表,c++,数据结构)