写完贴在这里 做
#include <iostream>
using namespace std;
class List
{
//内部类型成员
typedef int T;
//内部类型成员 受访问权限影响
struct Node
{
T data;
Node* next;
//一旦你写了构造函数 就不能再以前的方法初始化
// d = T() 零初始化 基本数据类型表示0 自定义数据类型表示无参构造函数
Node(const T& d = T() ):data(d),next(NULL)
{
}
};
Node* head; //头指针,用来保存头节点地址 。 有头节点的链表这里直接是Node对象
int len;
public:
List():head(NULL),len(0) { }
~List()
{
clear();
}
//函数的返回值如果是List型的 一定要是指针或者引用
//如果以值类型返回,由于head都指向同一个地方 ,在临时变量析构时会释放链表中所有的空间
//个数 有n个数则返回n
int size() const
{
return len;
}
//前插
void push_front(const T& d)
{
/*
Node* p = new Node(d); //这里不可以用局部变量 因为局部变量会销毁
p->next = head;
head = p;
*/
insert(d,0);
}
//后插
void push_back(const T&d)
{
insert(d,size()); //少用一次变量 出错几率就少一次 len 与 size()的区别
}
//找链表中指向指定位置的指针
// 返回引用类型 保证返回的是指针本身
// 如果不是引用 那就是值传递了。
//pos 从0~n 有n+1个位置 0~n都可以插值 位置0~n-1是用来删除和修改的
//因为我想在将来改变返回的这个指针的指向,所以写引用。
//若是值传递,我在调用函数后只能得到一个相同指向的指针,这样只能修改指向的对象的值
//,但却无法修改返回的这个指针的指向。
Node*& getptr(int pos)
{
if(pos == 0) return head;
Node *p = head;
//1 return p->next
//2 p=p->next ; return p->next
for(int i =1; i < pos; i++)
{
p = p->next;
}
return p->next;
}
//在任意位置插入
//1在链表里找到指向这个位置的指针
//2 新节点指和找到的指针指向同一个地方
//3 指针指向新节点 ++len
void insert(const T& d,int pos) //n个节点 有n+1个插入 pos 0~n
{
if(pos <0 || pos > size() ) pos = 0;
Node* &p = getptr(pos); //继续引用
Node *pn = new Node(d);
pn -> next = p;
p = pn;
len ++;
}
//遍历
void travel() const
{
Node *p = head;
while(p != NULL)
{
cout << p->data << ' ';
p = p->next;
}
cout << endl;
}
//按位置删除
//插入可以有n+1个位置 删除有n个位置 0~n-1
//1找到指向这个节点的指针
//2 保存指针 为temp 指针指向这个节点的下一个节点
//3 释放temp的空间 --len
void erase(int pos)
{
if(pos < 0 || pos > size() -1) //无效位置
{
return;
}
Node* &p = getptr(pos);
Node *temp = p;
p = p->next;
delete temp;
--len;
}
//按数值来得到指向节点的指针
int find(T d)
{
Node *p = head;
int pos = 0;
while( p != NULL)
{
if( (p->data) == d ) return pos;
p = p->next;
pos ++;
}
return -1;
}
//按数值来删除节点 删除链表中所有的这个值
void remove(T d)
{
int pos;
while( (pos=find(d)) != -1 )
{
erase(pos);
}
}
//修改节点
void set(int pos ,T d)
{
if(pos < 0 || pos > size()-1) return;
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;
}
//链表反转
void reverse()
{
//因为前面用了指针的引用,让我出现疑惑
//这里为什么不用引用呢?
//因为无论是函数形参还是返回值都存在值传递的问题,导致实际操作的
//是一个相同指向的临时指针 。
//而这个函数中不存在传递问题,是对指针的直接操作。
Node *p = head;
Node *p_next = NULL;
Node *p_pre =NULL;
while(p != NULL)
{
p_next = p->next;
p->next = p_pre;
p_pre = p;
p = p_next;
}
head = p_pre;
}
//清空
void clear()
{
while(head != NULL)
{
Node* p = head->next;
delete head;
head = p;
}
head = NULL;
len = 0;
}
};
int main()
{
List l;
cout << sizeof(l) << endl; // 大小 8
l.push_front(1);//头插
l.push_front(10);
l.push_front(100);
l.travel(); //100 10 1
l.insert(1000,0);
l.travel();//1000 100 10 1
l.push_back(10000); //1000 100 10 1 10000
l.travel();
l.insert(70,-1); // pos不正确 纠正为0
l.travel();//70 1000 100 10 1 10000
l.insert(7000,200); //pos不正确 纠正为0
l.travel();//7000 70 1000 100 10 1 10000
l.erase(100); //无效的位置 直接返回
l.travel();//7000 70 1000 100 10 1 10000
l.erase(5);//删除5号位置 即第六个位置
l.travel(); //7000 70 1000 100 10 10000
//插入重复的值
l.insert(999,2);
l.insert(999,5);
l.insert(999,6);
l.travel();//7000 70 999 1000 100 999 999 10 10000
l.remove(999); //按值删除
l.travel();//7000 70 1000 100 10 10000
//修改
l.set( l.find(10) , 9 ); //将10改成9
l.travel();//7000 70 1000 100 9 10000
l.set(0,8);//将第0个改成8
l.travel();//8 70 1000 100 9 10000
cout << boolalpha << l.empty() << endl; //false
cout << l.front() << ' ' << l.back() << endl;//8 10000
//cout << l.getptr(l.size() -1)->data << endl;
cout << "reverse : ";
l.reverse();
l.travel();
// l.clear();清空
//清空
while( !l.empty() )
{
l.erase(0);
}
cout << "size :" << l.size() << endl;
return 0;
}