您的位置:首页 > 其它

带头结点与不带头结点的单链表-LinkList

2017-05-04 21:10 274 查看
单链表有两种形式:带头结点的单链表和不带头结点的单链表。

关于单链表L的基本操作跟带头结点的单链表的基本操作稍有不同,特别的是在删除函数和插入函数中都加入了对第一个结点的判断,因为在插入和删除中第一个结点和其他结点时操作不同,要改变链表头指针的值。而带头结点的单链表无论插入和删除第几个元素,其操作都是统一的。

接下来具体分析。

1.带头节点的链表的插入,首先使用临时变量p等于要插入之前的节点(不管具体的插入位置),之后不管要插入的节点x是插到链表头还是插到链表的其他位置都是如下语句:

x->next= p->next;

p->next = x;

2.不带头结点的链表的插入,若要插到链表的开头则

x->next = head->next;

head = x;//这里不再是head->next = x

若插到链表的其他位置则

p = 插入之前的节点

x->next = p->next;

p->next = x;

3.带头结点的链表的删除,不解释,同样不存在删除位置的差异。

4.不带头结点的链表的删除,删除第一个节点时,head=head->next。删除其他节点时,head的值不会改变。

综上所述,带头节点的单链表,不论删除和插入的位置如何,不需要修改head的值,不带头结点的单链表则需要修改head的值。所以单链表一般为带头结点的单链表。

下面是一个带头结点的单链表LinkList示例

1.辅助文件包Assistance.h

#ifndef __ASSISTANCE_H__                // 如果没有定义__ASSISTANCE_H__
#define __ASSISTANCE_H__                // 那么定义__ASSISTANCE_H__

// 辅助软件包

// ANSI C++标准库头文件
#include <cstring>                  // 标准串操作
#include <iostream>                 // 标准流操作
#include <limits>                   // 极限
#include <cmath>                    // 数据函数
#include <fstream>                  // 文件输入输出
#include <cctype>                   // 字符处理
#include <ctime>                    // 日期和时间函数
#include <cstdlib>                  // 标准库
#include <cstdio>                   // 标准输入输出
#include <iomanip>                  // 输入输出流格式设置
#include <cstdarg>                  // 支持变长函数参数
#include <cassert>                  // 支持断言
using namespace std;                // 标准库包含在命名空间std中

// 自定义类型
enum Status {SUCCESS, FAIL, UNDER_FLOW, OVER_FLOW,RANGE_ERROR, DUPLICATE_ERROR,
NOT_PRESENT, ENTRY_INSERTED, ENTRY_FOUND, VISITED, UNVISITED};

// 宏定义
#define DEFAULT_SIZE 1000           // 缺省元素个数
#define DEFAULT_INFINITY 1000000    // 缺省无穷大

// 辅助函数声明

char GetChar(istream &inStream = cin); // 从输入流inStream中跳过空格及制表符获取一字符

template <class ElemType >
void Swap(ElemType &e1, ElemType &e2);  // 交换e1, e2之值

template<class ElemType>
void Display(ElemType elem[], int n);   // 显示数组elem的各数据元素值

template <class ElemType>
void Write(const ElemType &e);          // 显示数据元素

// 辅助类
class Error;            // 通用异常类

char GetChar(istream &inStream)
// 操作结果:从输入流inStream中跳过空格及制表符获取一字符
{
char ch;                                // 临时变量
while ((ch = (inStream).peek()) != EOF  // 文件结束符(peek()函数从输入流中接受1
// 字符,流的当前位置不变)
&& ((ch = (inStream).get()) == ' '   // 空格(get()函数从输入流中接受1字符,流
// 的当前位置向后移1个位置)
|| ch == '\t'));                 // 制表符

return ch;                              // 返回字符
}

// 通用异常类
#define MAX_ERROR_MESSAGE_LEN 100
class Error
{
private:
// 数据成员
char message[MAX_ERROR_MESSAGE_LEN];// 异常信息

public:
//  方法声明
Error(const char *mes = "一般性异常!");  // 构造函数
~Error(void) {};                   // 析构函数
void Show() const;                  // 显示异常信息
};

// 通用异常类的实现部分
Error::Error(const char *mes)
// 操作结果:由mes构构通用异常对象
{
strcpy(message, mes);               // 复制异常信息
}

void Error::Show()const
// 操作结果:显示异常信息
{
cout << message << endl;            // 显示异常信息
}

template <class ElemType >
void Swap(ElemType &e1, ElemType &e2)
// 操作结果: 交换e1, e2之值
{
ElemType temp;      // 临时变量
// 循环赋值实现交换e1, e2
temp = e1;  e1 = e2;  e2 = temp;
}

template<class ElemType>
void Display(ElemType elem[], int n)
// 操作结果: 显示数组elem的各数据元素值
{
for (int i = 0; i < n; i++)
{   // 显示数组elem
cout << elem[i] << "  ";
}
cout << endl;
}

template <class ElemType>
void Write(const ElemType &e)
// 操作结果: 显示数据元素
{
cout << e << "  ";
}

#endif


2.节点声明Node.h

//
// Created by YYL on 2017/5/4.
//

#ifndef _NODE_H_
#define _NODE_H_

#include <afxres.h>

template <class T>
struct Node{
//数据元素
T data;
Node<T> *next;//指针域
//构造函数
Node();
Node(T e,Node<T> *next=NULL);
};

//实现部分
template <class T>
Node<T>::Node() {
next=NULL;
}

template<class T>
Node<T>::Node(T e, Node<T> *next) {
data=e;
this->next=next;//
}
#endif


3.单链表类的声明LinkList.h

//
// Created by YYL on 2017/5/4.
//

#ifndef _LK_LIST_H_
#define _LK_LIST_H_

#include "Node.h"
#include "Assistance.h"

//单链表类
template <class T>
class LinkList {
protected:
Node<T> *head;//头结点指针
int length;//单链表长度
public:
LinkList();
LinkList(T v[],int n);
virtual ~LinkList();

int getLength() const;
bool isEmpty() const;//判断单链表是否为空
bool clear();
void traverse(void (*vist)(const T &)) const;//遍历单链表
//指针函数作为参数,使用时只需传入函数即可实现传入 的函数遍历
int LocalElem(const T&) const;
Status GetElem(int position,T &e) const;//取出单链表position处的值并存入e中
Status SetElem(int position,const T &e);
Status DeleteElem(int position,T &e);
Status InsertElem(int position,const T &e);
Status InsertElem(const T &e);//在单链表尾删除

//构造函数
LinkList(const LinkList<T> &la);//复制构造函数
LinkList<T> &operator=(const LinkList<T> &la);//赋值运算符

};

#endif


4.单链表的实现LinkList.cpp

//单链表:一个节点由两个域组成,一个存放数据元素data,一个域指向该单链表中的下一个节点的指针
#include "LinkList.h"
template<class T>
LinkList<T>::LinkList() {
head=new Node<T>;
assert(head);
length=0;
}
//assert() 函数用法
// assert宏的原型定义在中,其作用是如果它的条件返回错误,则终止程序执行,原型定义:
//void assert( int expression );
//assert的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向stderr打印一条出错信息,
//然后通过调用 abort 来终止程序运行。
template <class T>
LinkList::LinkList(T *v, int n) {
Node<T> *p;
p=head=new Node<T>;

assert(head!=0);
for(int i=0;i<n;i++){
p->next=new Node<T>(v[i],NULL);
p=p->next;
}
length=n;
}

template <class T>
LinkList<T>::~LinkList() {
clear();
delete head;
}

template<class T>
int LinkList<T>::getLength() const {
return length;
}

template<class T>
bool LinkList<T>::isEmpty() const {
return head->next==NULL;
}

template<class T>
bool LinkList<T>::clear(){
Node<T> *p=head->next;
while (p!=NULL){
head->next=p->next;
delete p;
p=head->next;
}
length=0;
}

template<class T>
void LinkList<T>::traverse(void (*vist)(const T &) ) const {
Node<T>*p=head->next;
while(p!=NULL){
(*vist)(p->data);
p=p->next;
}
}
//元素定位函数
template<class T>
int LinkList<T>::LocalElem(const T &e) const {
Node<T> *p=head->next;
int count=1;
while(p!=NULL&&p->data!=e){
count++;
p=p->next;
}
return (p!=NULL)?count:0;
}
template <class T>//取出position处的值并存入e中
Status LinkList<T>::GetElem(int position, T &e) const {
if(position<1||position>length)
return RANGE_ERROR;
else{
Node<T> *p=head->next;
int count;
for(count=1;count<position;count++){
p=p->next;
}
e=p->data;
return ENTRY_FOUND;
}
}

template<class T>
Status LinkList::SetElem(int position, const T &e) {//设置元素
if(position<1||position>length)
return RANGE_ERROR;
else{
Node<T> *p=head->next;
int count;
for(count=1;count<position;count++)
p=p->next;
p->data=e;
return SUCCESS;
}
}

template<class T>//删除position处的元素
Status LinkList<T>::DeleteElem(int position, T &e) {
if(position<1||position>length)
return RANGE_ERROR;
else{
Node<T> *p=head,*q;
for(int i=1;i<position;i++){
p=p->next;
}
q = p->next;
p->next = q->next;//删除结点
e = q->data;
length--;
delete q;//释放被删的节点
return SUCCESS;
}
}

template<class T>//插入元素到指定位置
Status LinkList<T>::InsertElem(int position, const T &e) {
if(position<1||position>length)
return RANGE_ERROR;
else {
Node<T> *p=head,*q;
for(int i=0;i<position;i++){
p=p->next;
}
q = new Node<T>(e,p->next);
assert(q);
p->next = q;
length++;
return SUCCESS;
}
}

template <class T>
Status LinkList<T>::InsertElem(const T &e) {
Node<T> *p,*q;
q=new Node<T>(e,NULL);
assert(q);//q指针构造失败则终止运行
for(p=head;p->next!=NULL;p=p->next);
p->next=q;
length++;
return SUCCESS;
}

template<class T>//复制构造函数
LinkList<T>::LinkList(const LinkList<T> &la) {
int lalength=la.getLength();
T e;//存放
head=new Node<T>;
assert(head);//头指针构造失败则终止运行
length=0;
for(int i=1;i<=lalength;i++){
la.GetElem(i,e);//取出第i个元素的值放入e中
InsertElem(e);//将e加到表尾
}
}

template <class T>
LinkList<T> &LinkList<T>::operator=(const LinkList<T> &la){
if(&la!=this){
int lalength=la.getLength();
T e;
clear();
for(int i=1;i<=lalength;i++){
la.GetElem(i,e);//取出第i个元素的值放入e中
InsertElem(e);//将e加到表尾
}
}
return *this;
}


不带头结点

#include <iostream>
using namespace std;
template<class Type>
//定义结点
struct Node
{
Type data;
Node<Type> *next;
};
//定义链表
template<class Type>
class LinkList
{
protected:
int len;//链表中结点个数
Node<Type>* Head; //不使用头结点
public:
LinkList();//默认构造函数
LinkList(const LinkList<Type>& otherList);//拷贝构造函数
~LinkList();
void createListForward();//头插法
void createBackward();//尾插法
void initList();//生成头结点,尾部设置为NULL
bool isEmptyList();
int  length();
void destoryList();
void getFirstData(Type& firstItem);
void getData(int pos,Type& firstItem);
void insertFirst(Type newItem);
void insertLast(Type newItem);
void deleteFirst(Type& data);
void deleteLast();
void reverse();
const LinkList<Type>& operator=(const LinkList<Type>&otherList);
friend ostream& operator<< <>(ostream& cout,const LinkList<Type>& list);
};

template<class Type>
LinkList<Type>::LinkList() //初始化时,只有一个头结点,有head指向
{
Head = NULL;
len =0;
}

template<class Type>
LinkList<Type>::LinkList(const LinkList<Type>&otherList)
{
Head = NULL;
len = otherList.len;
Node<Type>* current;//自己链表的尾部元素
Node<Type>* otherListCurrent=otherList.Head;//otherListCurrent指向第一个元素
while(otherListCurrent!=NULL)//拷贝的目标不为空
{
for (int i=1;i<=otherList.len;i++)
{
Node<Type>* NewNode = new Node<Type>;
NewNode->data = otherListCurrent->data;
NewNode->next = NULL;
if (i==1)
{
Head = NewNode;
current = Head;
}
else
{
current->next = NewNode;
current = current->next;
}
otherListCurrent = otherListCurrent->next;
}
}

}

template<class Type>
const LinkList<Type>& LinkList<Type>::operator=(const LinkList<Type>&otherList)//赋值函数
{
Node<Type>* current;//current总是指向要插的位置的前一结点
Node<Type>* otherListCurrent=otherList.Head;//otherListCurrent指向第一个元素
if (this!=&otherList)//避免自己给自己赋值
{
if (Head!=NULL)
{
destoryList();//自己有结点,先销毁
}
if(otherListCurrent!=NULL)
{
bool first = true;
while(otherListCurrent!=NULL)
{
Node<Type>* newNode = new Node<Type>;
newNode->data = otherListCurrent->data;
newNode->next = NULL;
if (first)
{
Head = newNode;
current = Head;
first = false;
}
else
{
current->next = newNode;
current = current->next;
}
otherListCurrent = otherListCurrent->next;
}
}
}
return *this;//为了连续赋值
}

template<class Type>
LinkList<Type>::~LinkList()
{
destoryList();
}

template<class Type>
void LinkList<Type>::createListForward()//头插法
{
Node<Type>* newNode;
cout<<"输入链表长度:"<<endl;
cin>>len;
for (int i=1;i<=len;i++)
{
newNode = new Node<Type>;
cout<<"输入元素:"<<endl;
cin>>newNode->data;
newNode->next=Head;
Head = newNode; //每插入一个结点,都是要把它放在第一个结点的位置
}
}

template<class Type>
void LinkList<Type>::createBackward()//尾插法
{
Node<Type>* newNode;
Node<Type>* current;//总是指向最后一个节点
cout<<"输入链表长度:"<<endl;
cin>>len;
for (int i=1;i<=len;i++)
{
newNode = new Node<Type>;
cout<<"输入元素:"<<endl;
cin>>newNode->data;
newNode->next = NULL;
if (i==1)
{
Head = newNode;
current = Head;
}
else
{
current->next=newNode;
current = current->next;
}

}
}

template<class Type>
void LinkList<Type>::initList() //所有结点都销毁
{
destoryList();
len=0;
Head=NULL;
}

template<class Type>
bool LinkList<Type>::isEmptyList()
{
if (Head==NULL)
{
return true;
}
else
{
return false;
}
}

template<class Type>
int LinkList<Type>::length()
{
return len;
}

template<class Type>
void LinkList<Type>::destoryList()//销毁包括头结点
{
Node<Type>* current;
while(Head!=NULL)
{
current = Head;
Head = current->next;
delete current;
}
Head=NULL;
len=0;
}

template<class Type>
void LinkList<Type>::getFirstData(Type& firstItem)
{
if (!isEmptyList())
{
firstItem = Head->data;
}
else
{
cout<<"链表为空!"<<endl;
}
}

template<class Type>
void LinkList<Type>::getData(int pos,Type& newItem)
{
if (pos<1 || pos>len)
{
cout<<"位置不当!"<<endl;
}
else
{
Node<Type>* current = Head;
for (int i=1;i<pos;i++)
{
current = current->next;
}
newItem = current->data;
}
}

template<class Type>
void LinkList<Type>::insertFirst(Type newItem)
{
Node<Type> *newNode = new Node<Type>;
newNode->data = newItem;
newNode->next = Head;
Head= newNode;
len++;
}

template<class Type>
void LinkList<Type>::insertLast(Type newItem)
{
Node<Type>* current = Head;
while(current!=NULL && current->next!=NULL)
{
current = current->next;
}
Node<Type> *newNode = new Node<Type>;
newNode->data = newItem;
if (current==NULL)//链表为空
{
newNode->next = current;
current = newNode;
}
else
{
newNode->next = current->next;
current->next = newNode;
}
len++;
}

template<class Type>
void LinkList<Type>::deleteFirst(Type& data)
{
if (!isEmptyList())
{
data = Head->data;
Node<Type>* temp = Head;
Head = Head->next;
delete temp;
}
else
{
cout<<"栈空!"<<endl;
}
len--;
}

template<class Type>
void LinkList<Type>::deleteLast()
{
Node<Type>* current = Head;
if (isEmptyList())
{
cout<<"链表为空!"<<endl;
}
else
{
for (int i=1;i<len-1;i++)
{
current = current->next;
}
Node<Type>* nextCurrent = current->next;
current->next = nextCurrent->next;
delete nextCurrent;
}
len--;

}

template<class Type>
void LinkList<Type>::reverse()
{
Node<Type>* current = Head;
Head=NULL;
if (current==NULL)
{
cout<<"链表为空!"<<endl;
}
else
{
while (current!=NULL)
{
Node<Type>* nextCurrent = current->next;
current->next = Head;
Head=current;
current = nextCurrent;
}
}
}

template<class Type>
ostream& operator<< <>(ostream& cout,const LinkList<Type>& list)
{
Node<Type>*current=list.Head; //有头结点,这是current指向第一个结点
if (current!=NULL)
{
while (current!=NULL)
{
cout<<current->data<<endl;
current=current->next;
}
}
else
{
cout<<"链表为空!"<<endl;
}
return cout;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: