STL中list详解

std::list

Lists are sequence containers that allow constant time insert and erase operations anywhere within the sequence, and iteration in both directions.
实际上,list容器就是一个双向链表,可以高效地进行插入删除元素。


list是C++标准模版库(STL,Standard Template Library)中的部分内容,list属于std命名域的内容,因此需要通过命名限定:using std::list;也可以直接使用全局的命名空间方式:using namespace std;


Member Functions(C++11)

一、构造函数、= 运算符

1. list。

(1) empty container constructor (default constructor)
Constructs an empty container, with no elements.
default (1)
explicit list (const allocator_type& alloc = allocator_type());
std::list<int> first;                                // empty list of ints

(2) fill constructor
Constructs a container with n elements. Each element is a copy of val (if provided).

fill (2)
explicit list (size_type n);
list (size_type n, const value_type& val,const allocator_type& alloc = allocator_type());
std::list<int> second (4,100);                       // four ints with value 100

(3) range constructor
Constructs a container with as many elements as the range [first,last), with each element emplace-constructed from its corresponding element in that range, in the same order.

range (3)
template <class InputIterator>
list (InputIterator first, InputIterator last, const allocator_type& alloc = allocator_type());
std::list<int> third (second.begin(),second.end());  // iterating through second

(4) copy constructor (and copying with allocator)

Constructs a container with a copy of each of the elements in x, in the same order.

copy (4)
list (const list& x);
list (const list& x, const allocator_type& alloc);
std::list<int> fourth (third);                       // a copy of third

(5) move constructor (and moving with allocator)

Constructs a container that acquires the elements of x.
If alloc is specified and is different from x’s allocator, the elements are moved. Otherwise, no elements are constructed (their ownership is directly transferred).
x is left in an unspecified but valid state.

move (5)
list (list&& x);
list (list&& x, const allocator_type& alloc);
 // the iterator constructor can also be used to construct from arrays:
int myints[] = {16,2,77,29};
std::list<int> fifth (myints, myints + sizeof(myints) / sizeof(int) );

2. operator=。

The copy assignment (1) copies all the elements from x into the container (with x preserving its contents).

copy (1)
list& operator= (const list& x);
std::list<int> first (3);      // list of 3 zero-initialized ints
std::list<int> second (5);     // list of 5 zero-initialized ints

second = first;                // list of 3 zero-initialized ints

二、返回迭代器类的函数

迭代器初始位置结束位置
正向迭代器std::list::beginstd::list::end
反向迭代器std::list::rbeginstd::list::rend

举例: 示意图
说明:begin指向第一个元素,黄色箭头。end是最后一个元素的后一个位置,黑色箭头。Begin和end一般一起使用,按正序输出list。rbegin指逆序的第一个元素,即最后一个元素,蓝色箭头。rend指逆序的最后一个元素的前一个位置,即第一个元素的前一个位置,红色箭头。rbegin和rend一般一起使用,用于逆序输出list。

1.begin和end

int myints[] = {75,23,65,42,13};
std::list<int> mylist (myints,myints+5);

std::cout << "mylist contains:";
for (std::list<int>::iterator it=mylist.begin(); it != mylist.end(); ++it)
std::cout << ' ' << *it;

std::cout << '\n';

Output:

mylist contains: 75 23 65 42 13

2.rbegin和rend

int myints[] = {75,23,65,42,13};
std::list<int> mylist (myints,myints+5);

std::cout << "mylist backwards:";
for (std::list<int>::reverse_iterator rit=mylist.rbegin(); rit!=mylist.rend(); ++rit)
std::cout << ' ' << *rit;

std::cout << '\n';

Output:

mylist contains: 13 42 65 23 75

三、list的容量相关的函数

1.empty

Returns whether the list container is empty (i.e. whether its size is 0).

std::list::emptybool empty() const noexcept;

2.size

Returns the number of elements in the list container.

std::list::sizesize_type size() const noexcept;

3.resize

Resizes the container so that it contains n elements.

If n is smaller than the current container size, the content is reduced to its first n elements, removing those beyond (and destroying them).

If n is greater than the current container size, the content is expanded by inserting at the end as many elements as needed to reach a size of n. If val is specified, the new elements are initialized as copies of val, otherwise, they are value-initialized.

void resize (size_type n);
void resize (size_type n, const value_type& val);

// resizing list
#include <iostream>
#include <list>

int main ()
{
  std::list<int> mylist;

  // set some initial content:
  for (int i=1; i<10; ++i) mylist.push_back(i);

  mylist.resize(5);
  mylist.resize(8,100);
  mylist.resize(12);

  std::cout << "mylist contains:";
  for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;

  std::cout << '\n';

  return 0;
}

output

mylist contains: 1 2 3 4 5 100 100 100 0 0 0 0

四、修改lsit的函数

1.assign

In the range version (1), the new contents are elements constructed from each of the elements in the range between first and last, in the same order.

range (1)
template <class InputIterator>
void assign (InputIterator first, InputIterator last);

// list::assign
#include <iostream>
#include <list>

int main ()
{
  std::list<int> first;
  std::list<int> second;

  first.assign (7,100);                      // 7 ints with value 100

  second.assign (first.begin(),first.end()); // a copy of first

  int myints[]={1776,7,4};
  first.assign (myints,myints+3);            // assigning from array

  std::cout << "Size of first: " << int (first.size()) << '\n';
  std::cout << "Size of second: " << int (second.size()) << '\n';
  return 0;
}

output

Size of first: 3
Size of second: 7

2.push_front

Inserts a new element at the beginning of the list, right before its current first element. The content of val is copied (or moved) to the inserted element.

This effectively increases the container size by one.

std::list::push_frontvoid push_front (const value_type& val);

// list::push_front
#include <iostream>
#include <list>

int main ()
{
  std::list<int> mylist (2,100);         // two ints with a value of 100
  mylist.push_front (200);
  mylist.push_front (300);

  std::cout << "mylist contains:";
  for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;

  std::cout << '\n';
  return 0;
}

output

300 200 100 100

3.push_back

Adds a new element at the end of the list container, after its current last element. The content of val is copied (or moved) to the new element.

This effectively increases the container size by one.

std::list::push_backvoid push_back (const value_type& val);

// list::push_back
#include <iostream>
#include <list>

int main ()
{
  std::list<int> mylist;
  int myint;

  std::cout << "Please enter some integers (enter 0 to end):\n";

  do {
    std::cin >> myint;
    mylist.push_back (myint);
  } while (myint);

  std::cout << "mylist stores " << mylist.size() << " numbers.\n";

  return 0;
}

4.pop_front

Removes the first element in the list container, effectively reducing its size by one.

This destroys the removed element.

std::list::pop_frontvoid pop_front();


// list::pop_front
#include <iostream>
#include <list>

int main ()
{
  std::list<int> mylist;
  mylist.push_back (100);
  mylist.push_back (200);
  mylist.push_back (300);

  std::cout << "Popping out the elements in mylist:";
  while (!mylist.empty())
  {
    std::cout << ' ' << mylist.front();
    mylist.pop_front();
  }

  std::cout << "\nFinal size of mylist is " << mylist.size() << '\n';

  return 0;
}

output

Popping out the elements in mylist: 100 200 300
Final size of mylist is 0

5.pop_back

Removes the last element in the list container, effectively reducing the container size by one.

This destroys the removed element.

std::list::pop_backvoid pop_back();

// list::pop_back
#include <iostream>
#include <list>

int main ()
{
  std::list<int> mylist;
  int sum (0);
  mylist.push_back (100);
  mylist.push_back (200);
  mylist.push_back (300);

  while (!mylist.empty())
  {
    sum+=mylist.back();
    mylist.pop_back();
  }

  std::cout << "The elements of mylist summed " << sum << '\n';

  return 0;
}

output

The elements of mylist summed 600

6.insert

he container is extended by inserting new elements before the element at the specified position.

This effectively increases the list size by the amount of elements inserted.

single element (1)
iterator insert (iterator position, const value_type& val);
fill (2)
void insert (iterator position, size_type n, const value_type& val);
range (3)
template <class InputIterator>
void insert (iterator position, InputIterator first, InputIterator last);

// inserting into a list
#include <iostream>
#include <list>
#include <vector>

int main ()
{
  std::list<int> mylist;
  std::list<int>::iterator it;

  // set some initial values:
  for (int i=1; i<=5; ++i) mylist.push_back(i); // 1 2 3 4 5

  it = mylist.begin();
  ++it;       // it points now to number 2           ^

  mylist.insert (it,10);                        // 1 10 2 3 4 5

  // "it" still points to number 2                      ^
  mylist.insert (it,2,20);                      // 1 10 20 20 2 3 4 5

  --it;       // it points now to the second 20            ^

  std::vector<int> myvector (2,30);
  mylist.insert (it,myvector.begin(),myvector.end());
                                                // 1 10 20 30 30 20 2 3 4 5
                                                //               ^
  std::cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

Output:

mylist contains: 1 10 20 30 30 20 2 3 4 5

7.earse

Removes from the list container either a single element (position) or a range of elements ([first,last)).

This effectively reduces the container size by the number of elements removed, which are destroyed.

Return value
An iterator pointing to the element that followed the last element erased by the function call. This is the container end if the operation erased the last element in the sequence.

iterator erase (const_iterator position);
iterator erase (const_iterator first, const_iterator last);

// erasing from list
#include <iostream>
#include <list>

int main ()
{
  std::list<int> mylist;
  std::list<int>::iterator it1,it2;

  // set some values:
  for (int i=1; i<10; ++i) mylist.push_back(i*10);

                              // 10 20 30 40 50 60 70 80 90
  it1 = it2 = mylist.begin(); // ^^
  advance (it2,6);            // ^                 ^
  ++it1;                      //    ^              ^

  it1 = mylist.erase (it1);   // 10 30 40 50 60 70 80 90
                              //    ^           ^

  it2 = mylist.erase (it2);   // 10 30 40 50 60 80 90
                              //    ^           ^

  ++it1;                      //       ^        ^
  --it2;                      //       ^     ^

  mylist.erase (it1,it2);     // 10 30 60 80 90
                              //        ^

  std::cout << "mylist contains:";
  for (it1=mylist.begin(); it1!=mylist.end(); ++it1)
    std::cout << ' ' << *it1;
  std::cout << '\n';

  return 0;
}

Output:

mylist contains: 10 30 60 80 90


删除list的值为4的元素

正确版本一:

//通过erase方法的返回值来获取下一个元素的位置
list<int>MyList;

for(int i = 0; i < 10; i ++)
{
    MyList.push_back(i);
}

list<int>::iterator it;

for(it = MyList.begin(); it != MyList.end();)
{
    if(*it == 4)
    {
        it = MyList.earse(it);
    }
    else
    {
        it ++;
    }
}

正确版本二:

//在调用erase方法之前先使用 “++”来获取下一个元素的位置
list<int>MyList;

for(int i = 0; i < 10; i ++)
{
    MyList.push_back(i);
}

list<int>::iterator it;

for(it = MyList.begin(); it != MyList.end();)
{
    if(*it == 4)
    {
        MyList.earse(it++);
    }
    else
    {
        it ++;
    }
}

错误版本一:

//MyList.erase(it)在执行以后,it所指的对象已经被销毁,所以再对it进行操作是非法的,程序会出错
list<int>MyList;

for(int i = 0; i < 10; i ++)
{
    MyList.push_back(i);
}

list<int>::iterator it;

for(it = MyList.begin(); it != MyList.end();it++)
{
    if(*it == 4)
    {
        MyList.earse(it);
    }
}

错误版本二:

//++实际上可以看做是一个函数。
//对于++在后的情况(例如i++),函数在运行的时候
//将运算的数据i已经改变,但是函数的返回值是操作之前的数据
//所以在我们看来,i++好像是先进行了i的读取,才+1
list<int>MyList;

for(int i = 0; i < 10; i ++)
{
    MyList.push_back(i);
}

list<int>::iterator it;

for(it = MyList.begin(); it != MyList.end();)
{
    if(*it == 4)
    {
        MyList.earse(++it);
    }
    else
    {
        it ++;
    }
}

8.swap

Exchanges the content of the container by the content of x, which is another list of the same type. Sizes may differ.

After the call to this member function, the elements in this container are those which were in x before the call, and the elements of x are those which were in this. All iterators, references and pointers remain valid for the swapped objects.

void swap (list& x);

// swap lists
#include <iostream>
#include <list>

int main ()
{
  std::list<int> first (3,100);   // three ints with a value of 100
  std::list<int> second (5,200);  // five ints with a value of 200

  first.swap(second);

  std::cout << "first contains:";
  for (std::list<int>::iterator it=first.begin(); it!=first.end(); it++)
    std::cout << ' ' << *it;
  std::cout << '\n';

  std::cout << "second contains:";
  for (std::list<int>::iterator it=second.begin(); it!=second.end(); it++)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

Output:

first contains: 200 200 200 200 200
second contains: 100 100 100

9.clear

Removes all elements from the list container (which are destroyed), and leaving the container with a size of 0.

void clear() noexcept;

// clearing lists
#include <iostream>
#include <list>

int main ()
{
  std::list<int> mylist;
  std::list<int>::iterator it;

  mylist.push_back (100);
  mylist.push_back (200);
  mylist.push_back (300);

  std::cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  mylist.clear();
  mylist.push_back (1101);
  mylist.push_back (2202);

  std::cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

Output:

mylist contains: 100 200 300
mylist contains: 1101 2202

五、操作类函数

1.splice

std::list::splice
void splice(const_iterator position, list& x);
void splice (const_iterator position, list&& x);
void splice (const_iterator position, list& x, const_iterator i);
void splice (const_iterator position, list&& x, const_iterator i);
void splice (const_iterator position, list& x, const_iterator first, const_iterator last);
void splice (const_iterator position, list&& x, const_iterator first, const_iterator last);

Transfers elements from x into the container, inserting them at position.

This effectively inserts those elements into the container and removes them from x, altering the sizes of both containers. The operation does not involve the construction or destruction of any element. They are transferred, no matter whether x is an lvalue or an rvalue, or whether the value_type supports move-construction or not.

The first version (1) transfers all the elements of x into the container.
The second version (2) transfers only the element pointed by i from x into the container.
The third version (3) transfers the range [first,last) from x into the container.


// splicing lists
#include <iostream>
#include <list>

int main ()
{
  std::list<int> mylist1, mylist2;
  std::list<int>::iterator it;

  // set some initial values:
  for (int i=1; i<=4; ++i)
     mylist1.push_back(i);      // mylist1: 1 2 3 4

  for (int i=1; i<=3; ++i)
     mylist2.push_back(i*10);   // mylist2: 10 20 30

  it = mylist1.begin();
  ++it;                         // points to 2

  mylist1.splice (it, mylist2); // mylist1: 1 10 20 30 2 3 4
                                // mylist2 (empty)
                                // "it" still points to 2 (the 5th element)

  mylist2.splice (mylist2.begin(),mylist1, it);
                                // mylist1: 1 10 20 30 3 4
                                // mylist2: 2
                                // "it" is now invalid.
  it = mylist1.begin();
  std::advance(it,3);           // "it" points now to 30

  mylist1.splice ( mylist1.begin(), mylist1, it, mylist1.end());
                                // mylist1: 30 3 4 1 10 20

  std::cout << "mylist1 contains:";
  for (it=mylist1.begin(); it!=mylist1.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  std::cout << "mylist2 contains:";
  for (it=mylist2.begin(); it!=mylist2.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

2.remove

Removes from the container all the elements that compare equal to val. This calls the destructor of these objects and reduces the container size by the number of elements removed.

void remove (const value_type& val);

// remove from list
#include <iostream>
#include <list>

int main ()
{
  int myints[]= {17,89,7,14};
  std::list<int> mylist (myints,myints+4);

  mylist.remove(89);

  std::cout << "mylist contains:";
  for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

3.remove_if

Removes from the container all the elements for which Predicate pred returns true. This calls the destructor of these objects and reduces the container size by the number of elements removed.

The function calls pred(*i) for each element (where i is an iterator to that element). Any of the elements in the list for which this returns true, are removed from the container.

template <class Predicate>void remove_if (Predicate pred);

// list::remove_if
#include <iostream>
#include <list>

// a predicate implemented as a function:
bool single_digit (const int& value) { return (value<10); }

// a predicate implemented as a class:
struct is_odd {
  bool operator() (const int& value) { return (value%2)==1; }
};

int main ()
{
  int myints[]= {15,36,7,17,20,39,4,1};
  std::list<int> mylist (myints,myints+8);   // 15 36 7 17 20 39 4 1

  mylist.remove_if (single_digit);           // 15 36 17 20 39

  mylist.remove_if (is_odd());               // 36 20

  std::cout << "mylist contains:";
  for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

4.sort

Sorts the elements in the list, altering their position within the container.

The sorting is performed by applying an algorithm that uses either operator< (in version (1)) or comp (in version (2)) to compare elements. This comparison shall produce a strict weak ordering of the elements (i.e., a consistent transitive comparison, without considering its reflexiveness).

The resulting order of equivalent elements is stable: i.e., equivalent elements preserve the relative order they had before the call.

The entire operation does not involve the construction, destruction or copy of any element object. Elements are moved within the container.

void sort();
template <class Compare> void sort (Compare comp);

// list::sort
#include <iostream>
#include <list>
#include <string>
#include <cctype>

// comparison, not case sensitive.
bool compare_nocase (const std::string& first, const std::string& second)
{
  unsigned int i=0;
  while ( (i<first.length()) && (i<second.length()) )
  {
    if (tolower(first[i])<tolower(second[i])) return true;
    else if (tolower(first[i])>tolower(second[i])) return false;
    ++i;
  }
  return ( first.length() < second.length() );
}

int main ()
{
  std::list<std::string> mylist;
  std::list<std::string>::iterator it;
  mylist.push_back ("one");
  mylist.push_back ("two");
  mylist.push_back ("Three");

  mylist.sort();

  std::cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  mylist.sort(compare_nocase);

  std::cout << "mylist contains:";
  for (it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

Output:

mylist contains: Three one two
mylist contains: one Three two

For default strings, the comparison is a strict character code comparison, where all uppercase letters compare lower than all lowercase letters, putting all strings beginning by an uppercase letter before in the first sorting operation.

Using the function compare_nocase the comparison is made case insensitive.

5.merge

Merges x into the list by transferring all of its elements at their respective ordered positions into the container (both containers shall already be ordered).

This effectively removes all the elements in x (which becomes empty), and inserts them into their ordered position within container (which expands in size by the number of elements transferred). The operation is performed without constructing nor destroying any element: they are transferred, no matter whether x is an lvalue or an rvalue, or whether the value_type supports move-construction or not.

The template versions with two parameters (2), have the same behavior, but take a specific predicate (comp) to perform the comparison operation between elements. This comparison shall produce a strict weak ordering of the elements (i.e., a consistent transitive comparison, without considering its reflexiveness).

This function requires that the list containers have their elements already ordered by value (or by comp) before the call. For an alternative on unordered lists, see list::splice.

Assuming such ordering, each element of x is inserted at the position that corresponds to its value according to the strict weak ordering defined by operator< or comp. The resulting order of equivalent elements is stable (i.e., equivalent elements preserve the relative order they had before the call, and existing elements precede those equivalent inserted from x).

The function does nothing if (&x == this).

void merge (list& x);
template <class Compare> void merge (list& x, Compare comp);
// list::merge
#include <iostream>
#include <list>

// compare only integral part:
bool mycomparison (double first, double second)
{ return ( int(first)<int(second) ); }

int main ()
{
  std::list<double> first, second;

  first.push_back (3.1);
  first.push_back (2.2);
  first.push_back (2.9);

  second.push_back (3.7);
  second.push_back (7.1);
  second.push_back (1.4);

  first.sort();
  second.sort();

  first.merge(second);

  // (second is now empty)

  second.push_back (2.1);

  first.merge(second,mycomparison);

  std::cout << "first contains:";
  for (std::list<double>::iterator it=first.begin(); it!=first.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

Output:

first contains: 1.4 2.2 2.9 2.1 3.1 3.7 7.1

Notice how in the second merger, the function mycomparison (which only compares the integral parts) did not consider 2.1 lower than 2.2 or 2.9, so it was inserted right after them, before 3.1.

6.reverse

Reverses the order of the elements in the list container.

void reverse();

// reversing list
#include <iostream>
#include <list>

int main ()
{
  std::list<int> mylist;

  for (int i=1; i<10; ++i) mylist.push_back(i);

  mylist.reverse();

  std::cout << "mylist contains:";
  for (std::list<int>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;

  std::cout << '\n';

  return 0;
}

Output:

mylist contains: 9 8 7 6 5 4 3 2 1

7.unique

The version with no parameters (1), removes all but the first element from every consecutive group of equal elements in the container.

Notice that an element is only removed from the list container if it compares equal to the element immediately preceding it. Thus, this function is especially useful for sorted lists.

The second version (2), takes as argument a specific comparison function that determine the “uniqueness” of an element. In fact, any behavior can be implemented (and not only an equality comparison), but notice that the function will call binary_pred(i,(i-1)) for all pairs of elements (where i is an iterator to an element, starting from the second) and remove i from the list if the predicate returns true.

The elements removed are destroyed.

void unique();
template <class BinaryPredicate> void unique (BinaryPredicate binary_pred);

// list::unique
#include <iostream>
#include <cmath>
#include <list>

// a binary predicate implemented as a function:
bool same_integral_part (double first, double second)
{ return ( int(first)==int(second) ); }

// a binary predicate implemented as a class:
struct is_near {
  bool operator() (double first, double second)
  { return (fabs(first-second)<5.0); }
};

int main ()
{
  double mydoubles[]={ 12.15,  2.72, 73.0,  12.77,  3.14,
                       12.77, 73.35, 72.25, 15.3,  72.25 };
  std::list<double> mylist (mydoubles,mydoubles+10);

  mylist.sort();             //  2.72,  3.14, 12.15, 12.77, 12.77,
                             // 15.3,  72.25, 72.25, 73.0,  73.35

  mylist.unique();           //  2.72,  3.14, 12.15, 12.77
                             // 15.3,  72.25, 73.0,  73.35

  mylist.unique (same_integral_part);  //  2.72,  3.14, 12.15
                                       // 15.3,  72.25, 73.0

  mylist.unique (is_near());           //  2.72, 12.15, 72.25

  std::cout << "mylist contains:";
  for (std::list<double>::iterator it=mylist.begin(); it!=mylist.end(); ++it)
    std::cout << ' ' << *it;
  std::cout << '\n';

  return 0;
}

Output:

mylist contains: 2.72 12.15 72.25



示例代码摘自c++reference

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值