单链表的实现:
功能:
1)缺省构造函数、复制构造函数(深复制)(先定义赋值操作符)、赋值操作符,析构函数。
2)empty/size函数。虽然这两个函数比较简单,但是函数的内容会持续出现,为了避免重复代码以及方便调试,一定要使用函数。就算他很简单。
3)insert\erase函数,完成最基本的添加\删除功能。
4)clear函数,用于析构函数。
5)sort函数,用于排序,最好把指针排序,而不是简单地调整数值。
6)tostring函数,用于输出表达。
主文件:
#include <iostream>
#include <string>
#include "list.hpp"
using std::cin;
using std::cout;
using std::endl;
using std::string;
int main() {
list li;
int n;
cin >> n;
for (int i = 0, data, pos; i < n; i++) {
cin >> pos >> data;
li.insert(pos, data);
}
cout << li.toString() << " size: " << li.size() << endl;
list li2(li);
list li3;
li = li3 = li2 = li;
cout << li.toString() << " size: " << li.size() << endl;
cout << li2.toString() << " size: " << li2.size() << endl;
cout << li3.toString() << " size: " << li3.size() << endl;
int m;
cin >> m;
for (int i = 0, pos; i < m; i++) {
cin >> pos;
li.erase(pos);
}
cout << li.toString() << endl;
cout << li.sort().toString() << endl;
cout << li2.sort().toString() << endl;
cout << li3.sort().toString() << endl;
return 0;
}
#ifndef LIST
#define LIST
#include <string>
#include <iostream>
typedef struct node {
int data;
struct node* next;
node(int data = 0, struct node* next = NULL) : data(data), next(next) {}
} node;
class list {
private:
node* head;
int _size;
public:
list();
list(const list&);
list& operator=(const list&);
~list();
// Capacity
bool empty(void) const;
int size(void) const;
public:
// output
// list: [1,2,3,4,5]
// output: 1->2->3->4->5->NULL
std::string toString(void) const;
void insert(int position, const int& data);
void erase(int position);
void clear(void);
#endif
#include "list.hpp"
#include <string>
#include <sstream>
list::list() {
this->head = NULL;
this->_size = 0;
}
list::list(const list& another) {
this->head = NULL;
this->_size = 0;
// 先要初始化*this指针,不然会出现内存泄露。
*(this) = another;
}
list& list::operator=(const list& another) {
if (this != &another) { // 如果左值和右值相同(地址相同),则不做处理。
this->clear();//清空左值。
if (another.head != NULL) {
this->head = new node(another.head->data);
node* p = another.head->next;
node* q = this->head;
while (p != NULL) {
q->next = new node(p->data);
p = p->next;
q = q->next;
}
q->next = NULL;
}
this->_size = another._size;
}
return *(this);
}
list::~list() { this->clear(); }
void list::clear() {
if (this->head != NULL) {
node* p = this->head;
//定义一个临时变量来做遍历删除。不要用head来遍历。
while (p != NULL) {
node* temp = p;
p = p->next;
delete temp;
}
this->head = NULL;
// 最后还要把head指针设为NULL!!!
}
this->_size = 0;
}
bool list::empty(void) const { return this->_size == 0; }
int list::size(void) const { return this->_size; }
std::string list::toString(void) const {
node* positioner = this->head;
std::string result;
std::stringstream ss;
while (positioner != NULL) {
ss << positioner->data;
std::string temp;
ss >> temp;
result += temp + "->";
ss.clear();
positioner = positioner->next;
}
result += "NULL";
return result;
}
void list::insert(int position, const int& data) {
if (position > this->_size || position < 0) {
return;
} else if (position == 0) {
// 如果position==0,要在head前加node。
node* temp = new node(data, this->head);
this->head = temp;
} else {
node* p = this->head;
int counter = 1;
while (counter != position) {
p = p->next;
counter++;
}
node* temp = new node(data, p->next);
p->next = temp;
}
this->_size++;
}
void list::erase(int position) {
if (position >= this->_size || position < 0) {
return;
} else if (position == 0) {
node* temp = this->head;
this->head = this->head->next;
delete temp;
} else {
node* pre = this->head;
int counter = 0;
while (counter != position - 1) {
counter++;
pre = pre->next;
}
node* temp = pre->next;
pre->next = temp->next;
delete temp;
}
this->_size--;
}
list& list::sort(void) {
if (this->head != NULL && this->head->next != NULL) {
node* slow = head;
node* fast = head->next;
while (fast != NULL) {
if (fast->data >= slow->data) {
fast = fast->next;
slow = slow->next;
} else {
node* pre = this->head;
// 如果head的值大于fast,就把fast调到head的位置
if (this->head->data > fast->data) {
slow->next = fast->next;
fast->next = this->head;
this->head = fast;
} else {
// 找到比fast大的指针,然后把fast指针调到该指针前面。
while (pre->next->data <= fast->data) {
pre = pre->next;
}
slow->next = fast->next;
fast->next = pre->next;
pre->next = fast;
}
// 还是让fast在slow前面。
fast = slow->next;
}
}
}
return *(this);
}
双向链表的实现:
功能:
1)复制控制操作。
2)基本的插入,删除。
3)list的主要功能。
主文件测试:
#include "List.hpp"
#include <iostream>
#include <string>
using std::cin;
using std::cout;
using std::endl;
using std::string;
bool condition1(list::listPointer p) { return true; }
bool condition2(list::listPointer p) {
if (p->data % 2 == 0) {
return false;
}
return true;
}
bool condition3(list::listPointer p) {
if (p->data > 5) {
return false;
}
return true;
}
void outputList(const list& li) {
cout << li << " size:" << li.size();
if (&li.front() == NULL) {
cout << " front:NULL";
} else {
cout << " front:" << li.front();
}
if (&li.back() == NULL) {
cout << " back:NULL";
} else {
cout << " back:" << li.back();
}
cout << endl;
}
int main() {
int n, m;
cin >> n >> m;
int* a = new int[n]();
for (int i = 0; i < n; i++) {
cin >> a[i];
}
if (true) {
list li1(a, n);
li1.insert(2, 111);
li1.push_front(150);
list li2(li1);
outputList(li1);
outputList(li2);
}
cout << endl;
if (true) {
list li1;
for (int i = 0; i < n; i++) {
li1.insert(i, a[i]);
}
for (int i = 0; i < m; i++) {
li1.erase(i);
}
outputList(li1);
}
cout << endl;
if (true) {
list li1(a, n), li2, li3;
li1 = li2 = li3 = li1;
outputList(li1);
li1.split(0, &li2, &li3);
outputList(li1);
outputList(li2);
outputList(li3);
li1.split(li1.size(), &li2, &li3);
outputList(li1);
outputList(li2);
outputList(li3);
li1.split(li1.size() / 2, &li2, &li3);
cout << li2.toString() << endl;
cout << li3.toString() << endl;
li1 += (li2 += li1).merge(li1, li1);
outputList(li1);
li1 += li3;
li2.merge(li1, li3);
for (int i = 0; i < li1.size(); i++) {
cout << li1[i] << " ";
}
cout << endl;
outputList(li2);
}
cout << endl;
cout << endl;
if (true) {
list li1(a, n);
li1.remove_if(condition1);
cout << li1 << " " << endl;
li1.assign(a, n);
li1.remove_if(condition2);
cout << li1 << endl;
li1.assign(a, n);
li1.remove_if(condition3);
outputList(li1);
}
cout << endl;
if (true) {
list li(a, n);
li.merge(li, li).merge(li, li).unique();
outputList(li);
}
delete[] a;
return 0;
}
头文件:
#ifndef LIST
#define LIST
#include <string>
#include <iostream>
class list {
public:
typedef int data_type;
struct node {
public:
data_type data;
node* next;
node* prev;
node(data_type data = 0, node* next = NULL, node* prev = NULL)
: data(data), next(next), prev(prev){};
};
typedef node listNode;
typedef node* listPointer;
typedef unsigned int size_type;
private:
listPointer head;
listPointer tail;
size_type _size;
inline listPointer at(int index) {
if (index >= 0 && index < this->_size) {
if (index <= this->_size / 2) {
int counter = 0;
listPointer p = this->head;
while (counter != index) {
counter++;
p = p->next;
}
return p;
} else {
int counter = 0;
listPointer p = this->tail;
while (counter != this->_size - 1 - index) {
counter++;
p = p->prev;
}
return p;
}
}
return NULL;
}
public:
list();
// construct a list from an exist array
list(const data_type[], int length);
list(const list&);
list& operator=(const list&);
~list();
// Capacity
bool empty(void) const;
size_type size(void) const;
// Element access
data_type& front(void) const;
data_type& back(void) const;
public:
// output
std::string toString(void) const;
// Modifiers
void assign(const list&);
void assign(const data_type datas[], int length);
void push_front(const data_type&);
void push_back(const data_type&);
void pop_front(void);
void pop_back(void);
void insert(int position, const data_type& data);
void erase(int position);
void clear(void);
// Operations
// split this list into to lists at the given position
void split(int position, list* des1, list* dest2);
// merge two list to this list from src1 and src2
list& merge(const list& src1, const list& src2);
// remove the elements who satisfy the condition
list& remove_if(bool (*condition)(listPointer));
// remove duplicate elements
list& unique(void);
// reverse the list
list& reverse(void);
// operators
data_type& operator[](int index);
list& operator+=(const list&);
friend std::ostream& operator<<(std::ostream& os, const list& li);
};
#endif
实现文件:
#include "List.hpp"
#include <string>
#include <sstream>
#include <assert.h>
#include <exception>
void list::clear() {
listPointer p = this->head;
listPointer q = NULL;
// 不要在循环里面定义q。因为这样内存消耗较大,每次都要定义一个q。
while (p != NULL) {
q = p;
p = p->next;
delete q;
}
this->head = NULL;
this->tail = NULL;
this->_size = 0;
// head要回到初始化。
}
list::list() {
this->head = this->tail = NULL;
this->_size = 0;
}
list::list(const list& another) {
this->head = this->tail = NULL;
this->_size = 0;
// 先初始化!再进行复制!
this->assign(another);
}
list::list(const data_type datas[], int length) {
this->head = this->tail = NULL;
this->_size = 0;
// 再说一遍!先初始化,在复制!
this->assign(datas, length);
}
list& list::operator=(const list& another) {
// 此处不用初始化是因为*this对象已经被初始化了,清空的操作在assign中完成。
this->assign(another);
return *(this);
}
list::~list() { this->clear(); }
bool list::empty() const { return this->_size == 0; }
list::size_type list::size() const { return this->_size; }
list::data_type& list::front() const {
return this->empty() ? *reinterpret_cast<data_type*>(NULL) : head->data;
}
/* reinterpret_cast<type-id> (expression)
type-id 必须是一个指针、引用、算术类型、函数指针或者成员指针。它可以把一个指针转换成一个整数,也可以把一个整数转换成一个指针(先把一个指针转换成一个整数,再把该整数转换成原类型的指针,还可以得到原先的指针值)。*/
// 在此处,如果链表是空,就返回一个NULL指针。
list::data_type& list::back() const {
return this->empty() ? *reinterpret_cast<data_type*>(NULL) : tail->data;
}
inline std::string int2String(int a) {
std::stringstream ss;
ss << a;
return ss.str();
}
/* 在tostring中会经常使用到整数转换为string类型,在这里定义为inline类型可以节省函数调用的开销,而且简化代码。*/
std::string list::toString(void) const {
if (this->_size == 0) {
return "NULL";
}
std::string ret;
listPointer p = this->head;
ret += "NULL<-";
while (p != NULL) {
ret += int2String(p->data);
if (p != this->tail) {
ret += "<->";
}
p = p->next;
}
ret += "->NULL";
return ret;
}
// 重载了两个assign。
void list::assign(const list& another) {
if (!(this == &another)) {
// 如果左值和右值相同,则不操作。
this->clear();
node* p = another.head;
while (p != NULL) {
this->push_back(p->data);
p = p->next;
}
}
}
void list::assign(const data_type datas[], int length) {
this->clear();
for (int i = 0; i < length; i++) {
this->push_back(datas[i]);
}
}
void list::push_front(const data_type& data) {
this->insert(0, data);
assert(this->head->data == data);
// 断言!如果没有插入成功,程序自动停止。方便代码维护。
}
void list::push_back(const data_type& data) {
this->insert(this->_size, data);
assert(this->tail->data == data);
}
void list::pop_front(void) { this->erase(0); }
void list::pop_back(void) { this->erase(this->_size - 1); }
void list::insert(int position, const data_type& data) {
if (position == 0) {
listPointer temp = new listNode(data, this->head);
this->head = temp;
assert(this->head != NULL);
if (this->_size == 0) {
this->tail = this->head;
} else {
this->head->next->prev = head;
}
this->_size++;
} else if (position == this->_size) {
listPointer temp = new listNode(data, NULL, this->tail);
this->tail->next = temp;
this->tail = this->tail->next;
this->_size++;
} else {
listPointer p = at(position - 1);
if (p != NULL) {
listPointer temp = new listNode(data, p->next, p);
p->next->prev = temp;
p->next = temp;
this->_size++;
assert(this->at(position)->data == data);
}
}
}
void list::erase(int position) {
if (this->empty()) return;
if (position == 0) {
if (this->_size == 1) {
delete this->head;
this->tail = this->head = NULL;
} else {
assert(head->next != NULL);
this->head = this->head->next;
delete this->head->prev;
this->head->prev = NULL;
/* 被delete掉的指针都要给定NULL。如果还要用到的话,例如head/tail的相关指针,因为被删除内存后,可能会指向系统内任意一个地址。*/
this->_size--;
}
} else if (position == this->_size - 1) {
this->tail = this->tail->prev;
assert(tail != NULL);
delete this->tail->next;
this->tail->next = NULL;
this->_size--;
} else {
listPointer p = at(position);
if (p != NULL) {
p->prev->next = p->next;
p->next->prev = p->prev;
delete p;
this->_size--;
}
}
}
void list::split(int position, list* dest1, list* dest2) {
if (dest1 == dest2) {
throw dest1;
return;
}
if (position < 0 || position > this->_size) return;
listPointer p = this->head;
int counter = 0;
list temp1, temp2;
while (p != NULL) {
if (counter == position) {
break;
}
temp1.push_back(p->data);
p = p->next;
counter++;
}
while (p != NULL) {
temp2.push_back(p->data);
p = p->next;
}
// 赋值操作符。
(*dest1) = temp1;
(*dest2) = temp2;
}
list& list::merge(const list& src1, const list& src2) {
list temp;
if (src1.empty()) {
temp = src2;
} else {
temp = src1;
listPointer p = src2.head;
while (p != NULL) {
temp.push_back(p->data);
p = p->next;
}
}
*(this) = temp;
return *(this);
}
list& list::remove_if(bool (*condition)(list::listPointer)) {
listPointer p = this->head;
while (p != NULL) {
if (condition(p)) {
if (p == this->head) {
this->head = this->head->next;
if (this->head != NULL) {
this->head->prev = NULL;
}
delete p;
this->_size--;
p = this->head;
if (p == NULL) {
this->tail = NULL;
}
} else if (p == this->tail) {
this->tail = this->tail->prev;
this->tail->next = NULL;
delete p;
this->_size--;
p = NULL;
} else {
p->prev->next = p->next;
p->next->prev = p->prev;
listNode* q = p->next;
delete p;
p = q;
this->_size--;
}
} else {
p = p->next;
}
}
return *(this);
}
list& list::unique(void) {
listPointer slow, fast;
slow = this->head;
while (slow != NULL) {
fast = slow->next;
while (fast != NULL) {
if (fast->data == slow->data) {
if (fast == this->head) {
this->head = this->head->next;
if (this->head != NULL) {
this->head->prev = NULL;
} else {
this->tail = NULL;
}
fast = this->head;
} else if (fast == this->tail) {
this->tail = this->tail->prev;
this->tail->next = NULL;
delete fast;
fast = NULL;
} else {
fast->next->prev = fast->prev;
fast->prev->next = fast->next;
listPointer temp = fast;
fast = fast->next;
delete temp;
}
this->_size--;
} else {
fast = fast->next;
}
}
slow = slow->next;
}
return *(this);
}
/* 提供一个非指针操作。*/
/*
list& list::unique() {
for (int i = 0; i != _size; i++) {
for (int j = i + 1; j != _size; j++) {
if (this->operator[](i) == this->operator[](j)) {
erase(j);
j--;
}
}
}
return *this;
}
*/
list& list::reverse(void) {
listPointer p = this->head;
while (p != NULL) {
listPointer q = p->prev;
p->prev = p->next;
p->next = q;
p = p->prev;
}
listPointer q = this->tail;
this->tail = this->head;
this->head = q;
return *(this);
}
list::data_type& list::operator[](int index) {
listPointer p = at(index);
assert(p != NULL);
return p->data;
}
list& list::operator+=(const list& another) {
return this->merge(*this, another);
}
std::ostream& operator<<(std::ostream& os, const list& li) {
return (os << li.toString());
}
ps:
1)对于链表问题,首先要通过画图,理解每一个操作的指针操作,然后在用语法表达。
2)其次,也是适用于一切工程问题,编程前,一定要明确每个函数如何完成,应该如何调用其他函数,什么函数的主要解决的,什么函数可以通过其他函数来完成。
对于类的完成要有大局观!