//node.h
#ifndef _NODE_H
#define _NODE_H
//定义一个结点类
template <class T>
class node{
private:
node<T>* next; //指针域
public:
T data; //数据域
node(const T& data, node<T>* next); //构造函数
void insertAfter(node<T>*p); //在当前结点后插入一个结点
node<T>* deleteAfter(); //删除当前结点后面的结点并返回其地址
node<T>* nextnode(); //返回后继结点地址
};
//构造函数实现
template<class T>
node<T>::node(const T& data, node<T>* next){
this->next = next;
this->data = data;
}
//在当前结点后插入一个结点
template<class T>
void node<T>::insertAfter(node<T>*p){
p->next = this->next;
this->next = p;
}
//删除当前结点后面的结点并返回其地址
template<class T>
node<T>* node<T>::deleteAfter(){
node<T> *n = this->next; //n用于存储删除结点的地址
if (this->next = NULL)
return NULL;
//n = next;
this->next = n->next;
return n;
}
//返回后继结点地址
template<class T>
node<T>* node<T>::nextnode(){
return this->next;
}
#endif
//链表.h
#ifndef _LIST_H
#define _LIST_H
#include <iostream>
#include <cstdlib>
#include "node.h"
using namespace std;
//生成结点:创建一个结点,数据成员为item,指向后继结点的指针为nextptr
template <class T>
node<T>* getnode(const T& item, node<T> *nextptr = NULL){
node<T>* newnode;
//为新结点分配内存空间,然后将item和nextptr传递给构造函数
newnode = new node<T>(item,nextptr);
if (newnode == NULL){//如果内存分配失败,则程序终止
cerr << "Memory allocation failure!" << endl;
exit(1);
}
return newnode;
}
//输出链表
enum AppendNewLine{noNewLine,addNewLine};
template <class T>
void printlist(node<T>*head, AppendNewLine addnl = noNewLine){
//currPtr初始指向表头结点,用于遍历链表
node<T>* currPtr = head;
//输出结点数据,直到链表结束
while (currPtr != NULL){
//如果换行标志addl= addnewline,则输出换行符
if (addnl == addNewLine)
cout << currPtr->data << endl;
else
cout << currPtr->data << " ";
currPtr = currPtr->nextnode();
}
}
//查找结点
template <class T>
int find(node<T>*head, T& item, node<T>* &prevptr){
node<T>*currPtr = head;
prevptr = NULL;
//通过循环遍历链表,直到表尾
while (currPtr != NULL){
//将item与结点的数据域相比较,如果相同则返回,不相同则继续执行
if (item == currPtr->data)
return 1;
prevptr = currPtr;
currPtr = currPtr->nextnode();
}
return 0;
}
//在表头插入结点
template <class T>
void insertfront(node<T>* &head, T item){
//建立新结点,使其指针域指向原链表头结点head,然后更新head
head = getnode(item, head);
}
//在表尾添加结点
template<class T>
void insertrear(node<T>* &head, const T& item){
node<T>* newnode, *currPtr = head;
//如果链表为空,则插入在表头
if (currPtr == NULL)
insertfront(head, item);
else{
//寻找指针域为NULL的点
while (currPtr->nextnode() != NULL)
currPtr = currPtr->nextnode();
//建立新结点并插入在表尾(在currPtr之后)
newnode = getnode(item);
currPtr->insertAfter(newnode);
}
}
//删除链表中第一个数据等于key的结点
template<class T>
void Delete (node<T>* &head, T key){
//currPtr用于遍历链表,prevPtr紧随其后
node<T> * currPtr = head, *prevPtr = NULL;
//如果链表为空,则返回
if (currPtr == NULL)
return;
while (currPtr != NULL && currPtr->data != key){
//currPtr前行,prevptr紧随其后
prevPtr = currPtr;
currPtr = currPtr->nextnode();
}
//若
if (currPtr != NULL){
if (prevPtr == NULL) //找到的是链表的第一个结点,直接删除
head = head->nextnode();
else
//如果找到的是第二个以后的结点,调用前趋结点的成员函数删除之
prevPtr->deleteAfter();
delete currPtr;
}
}
#endif
//链表类.cpp
#include "stdafx.h"
#include "node.h"
#include "链表.h"
#include <iostream>
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
//将表头指针置为NULL
node<int> *head = NULL, *prevPtr, *delPtr;
int key, item;
//输入10个整数依次向表头插入
for (int i = 0; i < 10; i++){
cin >> item;
insertfront(head, item);
}
//输出链表
cout << "List:";
printlist(head, noNewLine);
cout << endl;
//输入需要删除的整数
cout << "请输入一个需要删除的整数";
cin >> key;
//查找并删除结点
prevPtr = head;
if (find(head, key, prevPtr) != NULL){
if (prevPtr == NULL)
head = head->nextnode();
else
//如果找到的是第二个以后的结点,调用前趋结点的成员函数删除之
delPtr = prevPtr->deleteAfter();
//delete delPtr;
}
//输出链表
cout << "List:";
printlist(head, noNewLine);
cout << endl;
return 0;
}
今天在学习C++链表类的时候,照着书上的代码敲了一遍,敲完之后很有不少错误,回头看了一遍发现不少部分是因为我自己对C++错误的理解导致的,因此在这里mark一下。
1.公共的部分:
引用&是个好东西,可以在实现函数调用的时候利用子函数中引用对象的改变来改变主函数中相应对象的数值。
2.node.h中
在定义node的构造函数的时候,一开始形参顺序是指针+数据,就会报错,调整过来之后就OK了
3.链表类.cpp中
查找并删除结点原来的代码是用while循环,但是经过调试发现不对,while里面的find函数本身就是一个循环,再用while去判断肯定不对,因此把while改成了if,然后更改了代码就OK了
另外,当代码出现问题时,单步调试是个好办法。