单向链表
在 单向链表中引入 虚头结点,虚头结点不存储数据,在虚头结点之后的节点才开始存储数据;在增删 操作时,就不用将 头结点 单独考虑,统一实现逻辑。
含有 虚头结点 的链表, 如下图:
代码:
以模板类的形式实现的,只有一个头文件: linkedList.h
#ifndef SIMPLY_LINKEDLIST_LINKEDLIST_H
#define SIMPLY_LINKEDLIST_LINKEDLIST_H
#include <iostream>
template <class T>
class LinkedList{
private:
template <class >
class Node{
public:
T element;
Node<T>* next;
Node(){
element = T();
next = nullptr;
}
Node(T element, Node<T>* next):element(element){
// this->element = element;
this->next = next;
}
~Node()=default;
};
const int ELEMENT_NOT_FOUND = -1;
int Size;
Node<T>* first;
Node<T>* node(int index) const{
Node<T>* node = first->next;
for(int i=0; i < index; ++i){
node = node->next;
}
return node;
}
public:
LinkedList();
LinkedList(T element, Node<T>* next);
~LinkedList();
int size() const;
void clear();
bool contains(T element);
void add(T element);
void add(T element, int index);
T get(int index) const;
T set(T element, int index);
T remove(int index) ;
int getPos(T element);
void display() const;
};
template <class T>
LinkedList<T>::LinkedList():Size(0){
// Node<T>();
first = new Node<T>();
}
template <class T>
LinkedList<T>::LinkedList(T element, Node<T>* next):Size(0){
// Node<T>(element, next);
first = new Node<T>(element, next);
}
template <class T>
LinkedList<T>::~LinkedList() {
Node<T>* ptr = first;
int cnt = 0;
while(ptr != nullptr){
auto q = ptr->next;
delete ptr;
ptr = q;
++cnt;
}
first = nullptr;
std::cout << "...Finally, calling destructor...cnt-->: " << cnt << std::endl;
}
template <class T>
int LinkedList<T>::size() const {
return Size;
}
template <class T>
void LinkedList<T>::clear() {
Node<T>* node = first->next;
int cnt = 0;
for (int i=0; i < Size; ++i){
auto q = node->next;
delete node;
node = q;
++cnt;
}
Size = 0;
first->next = nullptr;
std::cout << "clear--->cnt: " << cnt << std::endl;
}
template <class T>
bool LinkedList<T>::contains(T element) {
return getPos(element) != ELEMENT_NOT_FOUND;
}
template <class T>
void LinkedList<T>::add(T element) {
add(element, Size);
}
template <class T>
void LinkedList<T>::add(T element, int index) {
Node<T>* prev = index == 0 ? first:node(index-1);
prev->next = new Node<T>(element, prev->next);
++Size;
}
template <class T>
T LinkedList<T>::get(int index) const{
return node(index)->element;
}
template <class T>
T LinkedList<T>::set(T element, int index) {
Node<T>* ptr = node(index);
T old = ptr->element;
ptr->element = element;
return old;
}
template <class T>
T LinkedList<T>::remove(int index) {
Node<T>* prev = index == 0 ? first:node(index-1);
auto oldPtr = prev->next;
prev->next = prev->next->next;
T old = oldPtr->element;
--Size;
delete oldPtr; // 删除节点后,释放 new 出来的 内存;
return old;
}
template <class T>
int LinkedList<T>::getPos(T element) {
int position = ELEMENT_NOT_FOUND;
Node<T>* ptr = first->next;
for (int i=0; i < Size; ++i){
if(element == ptr->element){
position = i;
break;
}
ptr = ptr->next;
}
return position;
}
template <class T>
void LinkedList<T>::display() const {
for(int i=0; i < Size; ++i){
std::cout << get(i) << " ";
}
std::cout << std::endl;
}
#endif //SIMPLY_LINKEDLIST_LINKEDLIST_H
测试代码
main.cpp
#include <iostream>
#include <utility>
#include "linkedList.h"
int main(){
// auto listPtr = new LinkedList_struct<T>();
auto listPtr = new LinkedList<T>(0, nullptr);
// function---->add()
listPtr->add(100, 0);
listPtr->add(10000, listPtr->size());
listPtr->add(20);
listPtr->add(500);
for (int i = 0; i < 10; ++i){
listPtr->add(i*100, i+2);
}
listPtr->display();
cout << "---------------------------------------------------------------------" << endl;
// function---->remove()
listPtr->remove(0);
T a = listPtr->remove(3);
cout << "a<--remove: " << a << endl;
listPtr->remove(listPtr->size()-1);
listPtr->display();
cout << "---------------------------------------------------------------------" << endl;
// function---->set()
a = listPtr->set(10, 0);
cout << "a<--set: " << a << endl;
a = listPtr->set(20000, listPtr->size()-1);
cout << "a<--set: " << a << endl;
a = listPtr->set(30000, 3);
cout << "a<--set: " << a << endl;
listPtr->display();
cout << "---------------------------------------------------------------------" << endl;
// function---->get()
a = listPtr->get(0);
cout << "a<--get: " << a << endl;
a = listPtr->get(listPtr->size()-1);
cout << "a<--get: " << a << endl;
a = listPtr->get(3);
cout << "a<--get: " << a << endl;
cout << "---------------------------------------------------------------------" << endl;
// function---->getPos()
int pos = listPtr->getPos(10);
cout << "pos(element->10): " << pos << endl;
pos = listPtr->getPos(20000);
cout << "pos(element->20000): " << pos << endl;
pos = listPtr->getPos(30000);
cout << "pos(element->30000): " << pos << endl;
cout << "---------------------------------------------------------------------" << endl;
// function---->contains()
bool tr = listPtr->contains(10);
cout << "true(1) or false(0): " << tr << endl;
tr = listPtr->contains(20000);
cout << "true(1) or false(0): " << tr << endl;
tr = listPtr->contains(-10);
cout << "true(1) or false(0): " << tr << endl;
cout << "---------------------------------------------------------------------" << endl;
// function---->clear()
listPtr->clear();
listPtr->display();
cout << "listPtr---->size: " << listPtr->size() << endl;
cout << "---------------------------------------------------------------------" << endl;
delete listPtr;
return 0;
}
运行结果:
E:\programme\C_C++\CLion\C++\algorithm\LinkedList\simply_LinkedList\cmake-build-debug\simply_LinkedList.exe
100 10000 0 100 200 300 400 500 600 700 800 900 20 500
---------------------------------------------------------------------
a<--remove: 200
10000 0 100 300 400 500 600 700 800 900 20
---------------------------------------------------------------------
a<--set: 10000
a<--set: 20
a<--set: 300
10 0 100 30000 400 500 600 700 800 900 20000
---------------------------------------------------------------------
a<--get: 10
a<--get: 20000
a<--get: 30000
---------------------------------------------------------------------
pos(element->10): 0
pos(element->20000): 10
pos(element->30000): 3
---------------------------------------------------------------------
true(1) or false(0): 1
true(1) or false(0): 1
true(1) or false(0): 0
---------------------------------------------------------------------
clear--->cnt: 11
listPtr---->size: 0
---------------------------------------------------------------------
...Finally, calling destructor...cnt-->: 1
Process finished with exit code 0
注意:
- 总共 14 个数据节点,删除 3 个,剩余 11 个节点,所以在清空节点时,释放了 11 个节点的堆内存。
- 最后1 个虚头结点,通过 析构函数 释放的,在 clear () 函数中,只是释放了剩余 11 个节点的申请的内存,当然也可以修改代码,在 clear() 释放所有节点。