#include <iostream>
using namespace std;
typedef int T;
class List{
struct Node{//结构体类型成员
T data;
Node* next;
Node(const T& d=T()):data(d),next(0){}
//T(),【零初始化】适用于所有类型参数
//对基本类型就是0;对自定义类型,就是建一个对象不传参数
};
Node * head;//头指针,用来保存头节点的地址。本身不是个节点,是一个指针。
//有很多数据结构的书,为了方便统一操作,把head定义为一个节点(Node head),
//本身(天生)自带一个节点的链表,称为”带头节点的链表“。
//而这里的head纯粹就是一个指针,就是一个纯粹的链表。
int len;
public:
List():head(NULL),len(0){//head初始化为NULL,代表这个链表中没有任何节点。【空链表】
Node n;//
}
void push_front(const T& d){//【***前插***】
/*Node* p = new Node(d);//必须使用“动态内存”new【链表中的节点都是动态创建的】
p->next = head;
head = p;*/
insert(d,0);
/* Node n(d); //push_front()函数一返回,节点n已不在了,此时head指向一个没了的地方。
* n.next = head; //所以必须保证出了这个函数,这个节点还在。且每次插入也必须新建节点。
* head=&n;*/
}
//List push_back(const T& d)//如果返回复制的一份链表,对复制的那份插入下一个数据。
//引用的重要性 //最后还有灾难,既然是复制的,两个链表对象的head是指向同一个地方
//引用的重要性 //两个对象的析构都会通过这个去delete,会出现“已放弃,double free”
//**** Error in `./a.out': double free or corruption (fasttop): 0x09846078 ***
//已放弃 (核心已转储)*/
List& push_back(const T& d){//【***尾插/后插***】
Node*& pn = getptr(len);
Node* p = new Node(d);
p->next = pn;
pn = p;
len++;
//insert(d,len);
//insert(d,size());
return *this;
}
int size()const {//返回节点的个数
//获取节点个数,有时需要花费空间,用空间换取时间。//增加len成员。
/*int cnt = 0;
Node* p = head; //从头开始遍历
while(p!=NULL){
++cnt;
p=p->next;
}
return cnt;*/
return len;
}
//方法:
//1.在链表里找到指向那个位置的指针。(想在哪个位置插入,就要找指向那个位置的指针)
// 如果位置是0,就返回head指针,如果是1,就是第1个节点的next指针,如果是k,就是第k个节点的next指针。
//C语言版本,此处需要用到二级指针。
//如果有n个节点,应该有n+1的位置可以插入。位置用0~n表示。
Node*& getptr(int pos){//必须返回Node*&,因为我们需要修改返回的next指针的值,修改复制没有意义。
if(pos<0||pos>size()) pos=0;
if(pos==0) return head;
Node* p = head;
for(int i =1;i<pos;i++){
p = p->next;
}
return (*p).next;//return p->next;//带回来原始指针
}
//2.让新节点的next成员和找到的那个指针指向同一个地方。
//3.让找到的那个指针指向新节点。
void insert(const T& d, int pos){//在任意位置插入。约定第一个位置按0表示,以此类推。
Node*& pn = getptr(pos);//用原始指针初始化p。只要哪个环节传递不是引用,就变成复制了。
Node* p = new Node(d);
p->next = pn;
pn = p;
++len;//每插入一个节点就加1。
}
void travel()const{//遍历
Node* p = head; //从头开始遍历
while(p!=NULL){
cout << p->data << ' ';
p=p->next;
}
cout << endl;
}
void clear(){ //清空这个链表
while(head!=NULL){
Node* temp = head->next;
delete head;
head = temp;
}
len = 0;
}
~List(){
cout << this << "******"<< head <<endl;//如果复制链表会出现多个对象对应同一个head
clear();
}
void erase(int pos){//按位置删除节点
if(pos<0||pos>=size()) return ;//有效位置为0-size()-1
//1.找到链表中指向那个位置的原始指针
//2.把那个指针另存为一份
//3.让那个指针指向下一个节点
//4.释放那个节点的内存
Node*& pn = getptr(pos);
Node* temp = pn;
pn = pn->next;
delete temp;
len--;
}
int find(const T& d){//根据数据,返回对应的位置pos
int pos = 0;
Node* p = head;
while(p){
if(p->data==d){
return pos;
}
p= p->next;
++pos;
}
return -1;
}
void remove(const T& d){//按数据删除节点
int pos ;
while((pos = find(d))!=-1){
erase(pos);
}
}
void set(int pos, const T&d){//根据提供的位置,修改成新数据
if(pos<0||pos>=size()) return ;//有效位置为0-size()-1
getptr(pos)->data = d;
}
bool empty()const{//是否为空
return head==NULL;
}
T front()const{//首节点
if(empty()) throw "空";
return head->data;
}
T back()const{//尾节点
if(empty()) throw "空";
Node* p = head;
while(p->next!=NULL){
p = p->next;
}
return p->data;
}
};
int main()
{
List l1;
l1.push_front(5);//5
l1.push_front(8);//8 5
l1.push_front(20);//20 8 5
l1.insert(9,2);//20 8 9 5
l1.insert(6,100);//6 20 8 9 5
l1.insert(7,-10);//7 6 20 8 9 5
l1.insert(1,2);//7 6 1 20 8 9 5
l1.travel();
List l2;
l2.push_back(5);//5
l2.push_back(8);//5 8
l2.push_back(20);//5 8 20
l2.push_back(8).push_back(20).push_back(3).push_back(20).push_back(6);
//5 8 20 8 20 3 20 6
l2.travel();
l2.erase(2); //5 8 8 20 3 20 6
l2.travel();
l2.remove(20);//5 8 8 3 6
l2.travel();
l2.set(0,55);
l2.set(4,66);
l2.set(l2.find(8),88);
l2.travel();//55 88 8 3 66
cout << l2.front() << "..." << l2.back() << endl;
while(!l2.empty()) l2.erase(0);
cout << "size of l2:" << l2.size() << endl;
cout << "sizeof(l2):" << sizeof(l2) << endl;
//如果给链表插了1000个节点后,sizeof(l1)值是8.
//因为对象l1里就一个指针成员head.类型Node*和一个int成员,共8个字节
return 0;
}
cy@cy-virtual-machine:~/C++$ ./a.out
7 6 1 20 8 9 5
5 8 20 8 20 3 20 6
5 8 8 20 3 20 6
5 8 8 3 6
55 88 8 3 66
55...66
size of l2:0
sizeof(l2):8
0xbfca20a8******0
0xbfca20a0******0x8100058