C++——list(线性双向链表)

1. 基本概念

list也是C++ STL中提供的一种容器,是线性的双向链表的数据结构。拥有链式结构的特征支持元素的快速插入和删除,但是元素随机访问较慢(相较于vector容器),不提供[]运算符的重载。C++中使用list容器需要包含头文件<list>,把list当做双向链表来看,可以记住list常用操作,如下:

  1. push_back():添加元素到list尾部。
  2. push_back():添加元素到list头部。
  3. pop_back():从list尾部删除元素。
  4. pop_front():从list头部删除元素。
  5. front():获得list头部元素。
  6. back():获得list尾部元素。
  7. merge():合并两个list(两个list必须事先有序)。
  8. sort():list排序,默认升序排序。

下面是一个示例:

#include <iostream>
#include <list>
#include <algorithm>
#include <vector>
#include <numeric>   
using namespace std;

void PrintIt(int& a) { cout << a << " "; }

int main()
{
	//list常用操作
	//push_back:添加元素到list尾部
	//push_front:添加元素到list头部
	//pop_back:从list尾部删除元素
	//pop_front:从list头部删除元素
	//front:获得list头部元素
	//back:获得list尾部元素
	//begin,end:迭代器,指向list头部和尾部元素
	//rbegin,rend:逆向迭代器
	//merge:合并两个list(两个list必须事先有序)
	//sort:list排序
	list<int> intListA;
	list<int> intListB;
	for (int i = 1; i < 11; i++)intListA.push_front(i);//intListA赋值10~1(降序)
	cout << "Elements in intListA: " << endl;
	for (auto it = intListA.begin(); it != intListA.end(); ) {//逐个打印并删除intListA中的元素
		cout << *it << " ";
		it = intListA.erase(it);
	}
	cout << endl;
	for (int i = 1; i < 11; i++)intListA.push_front(i);//intListA赋值10~1(降序)
	cout << "front: " << intListA.front() << " back: " << intListA.back() << endl;//打印intListA首、尾元素
	intListA.sort();//对intListA排序
	cout << "Elements in intListA after sort:" << endl;
	for (auto it = intListA.begin(); it != intListA.end(); it++)cout << *it << " ";//打印排序之后的intListA
	cout << endl;
	for (int j = 20; j > 10; --j)intListB.push_back(j);//intListB赋值20~11(降序)
	intListB.sort(less<int>());
	intListA.merge(intListB);//将intListB合并到intListA中
	cout << "Elements in intListA after merge intListA with intListB:" << endl;
	for (auto it = intListA.begin(); it != intListA.end(); it++)cout << *it << " ";//打印将intListB合并到intListA之后的intListA
	cout << endl;
	cout << "Elements in intListB after merge:" << endl;
	for_each(intListB.begin(), intListB.end(), PrintIt);//可以通过for_each,处理list中的每个元素
	cout << endl;
	cout << "intListB.size:" << intListB.size() << endl;

	return 0;
}

代码输出如下:

2. 使用C++创建线性双向单链表(LinkList)类

使用C++创建线性双向单链表类(命名为LinkList),实现的主要功能就是:1)支持在链表头、尾插入节点;2)可以获得链表头、尾节点的元素值;3)删除链表头、尾的节点;4)将链表按照从头到尾升序或者逆序排列;5)合并两个已经按照升序排列的链表;6)从头到尾打印链表节点;7)从尾到头打印链表节点。

类的声明在LinkList.h文件中,如下:

//声明线性双向单链表类(命名为LinkList),实现的主要功能就是:1)支持在链表头、尾插入节点;
//2)可以获得链表头、尾节点的元素值;3)删除链表头、尾的节点;4)将链表按照从头到尾升序或者逆序排列;
//5)合并两个已经按照升序排列的链表;6)从头到尾打印链表节点;7)从尾到头打印链表节点。
#pragma once
#include <iostream>
#include <set>
using namespace std;
class LinkList//线性双向链表类的定义
{
private:
	struct ListNode{//链表节点定义
		int val;
		ListNode* next;
		ListNode* prev;
		ListNode():val(-1),next(NULL),prev(NULL){}//构造函数
		ListNode(int x) :val(x), next(NULL), prev(NULL) {}
	};
	//注意,链表的头结点和尾节点不存放数据,只作为头尾指针使用
	ListNode* head;//链表头结点
	ListNode* rear;//链表尾节点
	multiset<int> keyVal;//用来顺序存放链表中所有节点的val,set底层实现是二叉树(红黑树)
	void clear();//清除链表和set
	ListNode* find(const int& key);
	void create_list();//创建链表头结点
	void insert(ListNode* prevNode, ListNode* newNode);//在prev节点后面插入新节点newNode
public:
	LinkList();
	LinkList(const LinkList& list2);
	~LinkList();
	
	void push_back(const int& key);//将元素添加到链表尾部
	void push_front(const int& key);//将元素添加到链表头部
	void pop_back();//将链表尾部元素删除
	void pop_front();//将链表头部元素删除
	void erase(const int& key);//找到链表指定元素并删除,如果存在多个相同的元素,则全部删除
	int back();//获得链表尾部的元素
	int front();//获得链表头部的元素
	void sort();//将链表按照升序排序
	void rsort();//将链表按照降序排序
	void print();//将链表从头到尾打印输出
	void rprint();//将链表从尾到头打印输出
	void merge(LinkList& list2);//将一个list合并到该list中
};

 类的实现在LinkList.cpp文件中:

//实现线性双向单链表类(命名为LinkList)
#include "pch.h"
#include "LinkList.h"

//默认构造函数
LinkList::LinkList(){
	create_list();
}
//复制构造函数
LinkList::LinkList(const LinkList & list2)
{
	create_list();
	keyVal.insert(list2.keyVal.begin(), list2.keyVal.end());
	ListNode* tmpNode = list2.head->next;
	ListNode* tmpHead = head;
	while (tmpNode != list2.rear) {
		ListNode* newNode = new ListNode(tmpNode->val);
		insert(tmpHead, newNode);
		tmpHead = tmpHead->next;
		tmpNode = tmpNode->next;
	}
}

LinkList::~LinkList() {
	clear();
}

void LinkList::clear()
{
	ListNode* tmpHead = head;
	while (tmpHead) {//从链表的头开始,进行删除操作
		ListNode* tmp1 = tmpHead->next;//新的链表的头节点
		//删除链表头节点
		delete tmpHead;
		//更新新的链表的头节点
		tmpHead = tmp1;
	}
	keyVal.clear();
}
//返回key的上一个节点
LinkList::ListNode* LinkList::find(const int & key)
{
	ListNode* tmpHead = head;
	for (; tmpHead->next; tmpHead = tmpHead->next) {
		if (tmpHead->next->val == key) return tmpHead;
	}
}

//初始化线性双链表
void LinkList::create_list()
{
	head = new ListNode();
	rear = new ListNode();
	head->next = rear;
	rear->prev = head;
}
//在prev节点后面插入新节点newNode
void LinkList::insert(ListNode * prevNode, ListNode * newNode)
{
	prevNode->next->prev = newNode;
	newNode->next = prevNode->next;//将新节点挂在next的前面
	prevNode->next = newNode;
	newNode->prev = prevNode;//将新节点挂在prev的后面
}
//将元素添加到链表尾部
void LinkList::push_back(const int & key)
{
	ListNode* newNode = new ListNode(key);
	rear->prev->next = newNode;
	newNode->prev = rear->prev;//将新节点续到原来节点后面

	newNode->next = rear;//将rear接到链表后面
	rear->prev = newNode;
	keyVal.insert(key);
}
//将元素添加到链表头部
void LinkList::push_front(const int & key)
{
	ListNode* newNode = new ListNode(key);
	head->next->prev = newNode;//将新节点添加到原来的头结点前面
	newNode->next = head->next;

	head->next = newNode;//将head节点接到头结点前面
	newNode->prev = head;
	
	keyVal.insert(key);
}
//将链表尾部元素删除
void LinkList::pop_back()
{
	ListNode* tmpNode = rear->prev;
	if (tmpNode == head)return;//rear->prev=head的时候,说明链表中还没有节点,此时直接返回
	auto it = keyVal.find(tmpNode->val);
	keyVal.erase(it);
	rear->prev = tmpNode->prev;
	tmpNode->prev->next = rear;
	delete tmpNode;
}
//将链表头部元素删除
void LinkList::pop_front()
{
	ListNode* tmpNode = head->next;
	if (tmpNode == rear)return;//head->next=rear的时候,说明链表中还没有节点,此时直接返回
	auto it = keyVal.find(tmpNode->val);
	keyVal.erase(it);
	head->next = tmpNode->next;
	tmpNode->next->prev = head;
	delete tmpNode;
}
//找到链表指定元素并删除,如果存在多个相同的元素,则全部删除
void LinkList::erase(const int & key)
{
	ListNode* tmpHead = head->next;
	for (; tmpHead != rear;) {//在整个链表中删除所有val=key的节点
		ListNode* tmp = tmpHead;
		tmpHead = tmpHead->next;
		if (tmp->val == key) {
			tmp->prev->next = tmp->next;
			tmp->next->prev = tmp->prev;
			delete tmp;
		}
	}
	keyVal.erase(keyVal.lower_bound(key), keyVal.upper_bound(key));//同时更新keyVal表
}
//获得链表尾部的元素
int LinkList::back()
{
	return rear->prev->val;
}
//获得链表头部的元素
int LinkList::front()
{
	return head->next->val;
}
//将链表按照升序排序
void LinkList::sort()
{
	ListNode* tmpNode = head->next;
	for (auto it=keyVal.begin(); it!=keyVal.end(); tmpNode = tmpNode->next, ++it) {
		tmpNode->val = (*it);
	}
}
//将链表按照降序排序
void LinkList::rsort()
{
	ListNode* tmpNode = rear->prev;
	for (auto it = keyVal.begin(); it != keyVal.end(); tmpNode = tmpNode->prev, ++it) {
		tmpNode->val = (*it);
	}
}
//将链表从头到尾打印输出
void LinkList::print()
{
	ListNode* tmpHead = head->next;
	for (; tmpHead!=rear; tmpHead = tmpHead->next) {
		cout << tmpHead->val << " ";
	}
	cout << endl;
}
//将链表从尾到头打印输出
void LinkList::rprint()
{
	ListNode* tmpRear = rear->prev;
	for (; tmpRear!=head; tmpRear = tmpRear->prev) {
		cout << tmpRear->val << " ";
	}
	cout << endl;
}
//将list2合并到list中
void LinkList::merge(LinkList & list2)
{
	ListNode* head1 = head->next;
	ListNode* head2 = list2.head->next;
	while (head1 != rear) {
		if (head2->val >= head1->val&&head2->val < head1->next->val) {
			ListNode* tmp1 = head1->next;
			ListNode* tmp2 = head2->next;
			insert(head1, head2);
			head2 = tmp2;
			if (head2 == list2.rear)return;
			head1 = tmp1;
		}
		head1 = head1->next;
	}
	head1->prev->next = head2;
	head2->prev = head1->prev;//将list2接到list1后面

	rear->prev = list2.rear->prev;
	list2.rear->prev->next = rear;//更新list1的rear
	list2.head->next = list2.rear;//初始化list2的head和rear
	list2.rear->prev = list2.head;
	keyVal.insert(list2.keyVal.begin(), list2.keyVal.end());//将list2的keyval合并到链表中
	list2.keyVal.clear();//清空list2的keyval
}


在main函数中调用LinkList类:

#include <iostream>
#include "LinkList.h"
using namespace std;
int main()
{
	LinkList list;//创建一个list
	for (int i = 10; i >= 1; i--)list.push_back(i);
	list.push_front(1);//给list赋值
	list.print();//从头到尾打印list
	list.sort();//list排序(升序)
	list.print();//从头到尾打印升序排序后的list
	list.erase(1);//从list中删除val=1的节点
	list.print();//打印删除val=1的节点之后的list
	cout << list.back() << " " << list.front() << endl;//打印list的头结点和尾节点元素
	list.rsort();//list按照从头到尾逆序排序
	list.print();//打印逆序排序之后的list
	list.sort();//重新将list进行升序排序
	LinkList list2;
	for (int i = 11; i <= 20; ++i)list2.push_back(i);
	list2.push_front(2);
	list2.push_front(5);//创建list2并赋值
	list2.sort();//list2按照升序排序(先排序,再进行merge)
	list2.print();//打印排好序的list2
	list.merge(list2);//将list2合并到list中
	list.print();//打印合并后的list
	LinkList list3(list);//使用拷贝构造函数,构造list3
	list3.print();//打印list3
	list3.pop_back();
	list3.pop_front();
	list3.print();
	return 0;
}

打印的输出如下:

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值