1. 基本概念
list也是C++ STL中提供的一种容器,是线性的双向链表的数据结构。拥有链式结构的特征:支持元素的快速插入和删除,但是元素随机访问较慢(相较于vector容器),不提供[]运算符的重载。C++中使用list容器需要包含头文件<list>,把list当做双向链表来看,可以记住list的常用操作,如下:
- push_back():添加元素到list尾部。
- push_back():添加元素到list头部。
- pop_back():从list尾部删除元素。
- pop_front():从list头部删除元素。
- front():获得list头部元素。
- back():获得list尾部元素。
- merge():合并两个list(两个list必须事先有序)。
- 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;
}
打印的输出如下: