数据结构学习笔记4——单链表的实现

线性表(list)的实现有两种标准方法:顺序表(array based list)和链表(linked list)。顺序表用数组实现,实现方法见上一节;链表用指针动态实现。链表又包括单链表(singly linked list)和双链表(doubly linked list)。本节讨论单链表的实现。

单链表的结构形式:

数据结构学习笔记4——单链表的实现_第1张图片

注意:

  1. Head的Val中不存储具体的数值,而Tail的next不再指向任意节点。
  2. Curr并非指向当前节点,而是指向当前节点的前一个节点,这样安排时为了便于实现插入操作(在当前节点前插入元素)

文件结构如下:

数据结构学习笔记4——单链表的实现_第2张图片

其中,Public.h、Tools.h、Tools.cpp为提供辅助功能的文件:Public.h包含常用的头文件,Tools.h和Tools.cpp实现了异常机制Assert();
List.h中实现线性表的抽象类模板,不包含数据成员,成员函数都是虚函数(当然构造函数除外);
Single_Linked_List.h和Single_Linked_List_Def.h实现单链表的模板类定义,其继承自List.h中的线性表模板;
main.cpp为主函数,实现单链表的调用和测试。


Lish.h的实现与前一节相同,实现线性表的抽象类模板:

/********************************************************/
// 用模板实现线性表(List)的基类定义
/********************************************************/
#pragma once
#include "Public.h"

template
class List
{
private:
	void operator= (const List&) {} //应该是无用的,可删除
	List(const List&) {}//构造函数不可为虚函数
public:
	List() {}         //默认构造函数,构造函数不可为虚函数
	virtual ~List(){} //析构函数,基类一般总是需要虚析构函数,以便基类指针指向派生类时,删除基类指针时收回空间
	
	// 清除内容,使线性表为空
	virtual void clear() = 0; //纯虚函数,被派生类的实现覆盖,任何对象都不能调用当前版本

	// 在当前位置插入元素
	virtual void insert(const dataType& item) = 0;

	// 在末尾追加元素
	virtual void append(const dataType& item) = 0;

	// 删除当前元素,返回其值
	virtual dataType remove() = 0;//不能返回引用,因为该元素已经被删除了,只能返回值

	// 将当前位置设为线性表的开始
	virtual void moveToStart() = 0;

	// 将当前位置设为线性表的末尾
	virtual void moveToEnd() = 0;

	// 将当前位置左移一格,若当前已经在开始位置则无改变
	virtual void prev() = 0;

	// 将当前位置右移一格,若当前已经在结束位置则无改变
	virtual void next() = 0;

	// 线性表中已经存储的元素的个数
	virtual int length() const = 0; //size_t或unsigned int不是更好?

	// 获取当前的位置
	virtual int currPos() const = 0; 

	// 将当前位置的元素移动到某个特定位置
	virtual void moveToPos(int pos) = 0;

	// 获取当前的元素
	virtual const dataType& getValue() const = 0; //const引用
};

Single_Linked_List.h:将整张单链表定义为一个类(模板)

/********************************************************/
// 用模板实现单向链表(Single Linked List)的定义
// 继承基类线性表template class List
/********************************************************/
#pragma once

#include "List.h"

// 1,定义节点类模板
template
class Node
{
public:
	E element; //本结点存储的元素值
	Node* next;//指向下一结点的指针
	Node(const E& elemval, Node* nextval = NULL):element(elemval),next(nextval){}
	Node(Node* nextval = NULL) :next(nextval) {}
};

// 2,定义链表类模板
template
class Single_LList : public List
{
private:
	Node* head; //表头,head结点内并不存储真是的元素
	Node* tail;
	Node* curr; //实际上curr->next才是真正的当前位置
	int cnt;       //链表中当前存储的元素个数
	void init();   //初始化
	void remove_all();  //清空
public:
	Single_LList();
	~Single_LList();

	void print() const;
	void clear();
	void insert(const E& it); //在当前位置插入元素
	void append(const E& it); //在链表末尾追加
	E    remove();            //删除当前的元素并返回其值
	void moveToStart();       //将当前位置设为链表开始
	void moveToEnd();         //将当前位置设为链表结束
	void prev();              //将当前位置左移一位
	void next();			  //将当前位置右移一位
	int  length() const;      //返回当前链表存储的元素个数
	int  currPos() const;     //返回当前位置
	void moveToPos(int pos);  //将当前位置设为指定位置
	const E& getValue() const;//返回当前位置的元素值
};

Single_Linked_List_Def.h:实现Single_Linked_List.h中的成员函数定义

/********************************************************/
// 用模板实现单向链表(Single Linked List)的定义
// 继承基类线性表 template class List
// 本头文件实现Single_LList的成员函数
/********************************************************/
#pragma once
#include "Single_Linked_List.h"

template
void Single_LList::init()
{
	//所有指针指向新开的空间
	head = tail = curr = new Node;
	cnt = 0;
}

//删除所有结点
template
void Single_LList::remove_all()
{
	while (head != NULL)
	{
		curr = head;	

		//请注意,下面两句的顺序不能颠倒,不然curr删除后就相当于head删除了,就不能再获取head->next了
		head = head->next;
		delete curr; 
	}	
}

//构造函数
template
Single_LList::Single_LList()
{
	//构造时只开辟一个节点的空间
	init();
}

//析构函数
template
Single_LList::~Single_LList()
{
	remove_all();
}

//打印所有元素
template
void Single_LList:: print() const
{
	Node* temp = head->next;
	while (NULL != temp)
	{
		//此处暗示类型E必须定义了“<<”操作,否则报错
		cout << temp->element << endl;
		temp = temp->next;
	}
}

//清空链表
template
void Single_LList::clear()
{
	remove_all();
	init(); //删除之后,还要留着表头
}

//当前位置插入元素
template
void Single_LList::insert(const E& it)
{
	//Node* temp = curr->next;
	//curr->next = new Node;
	//curr->next->element = it;
	//curr->next->next = temp;
	//这一句,代替了上面4句,调用了Node的构造函数
	curr->next = new Node(it, curr->next);

	//若本来curr就在尾部,则插入后新元素成为新的尾部,需要更新tail指针
	if (curr == tail)
	{
		tail = curr->next; //更新tail指针
	}

	//不要忘记增加结点计数
	cnt++;
}

//链表末尾追加元素
template
void Single_LList::append(const E& it)
{
	tail->next = new Node(it, NULL);
	tail = tail->next;
	cnt++;
}

//删除当前元素并返回其值
template
E Single_LList::remove()
{
	Assert(curr != tail, "当前位置无效,无法删除");
	Node* temp = curr->next;	
	E it = temp->element;

	if (temp == tail) //若删除的是末端元素,则需更新tail
	{
		tail = curr;
	}	
	curr->next = temp->next; //即便是temp为tail的时候,这句依然成立
	delete temp;

	cnt--;
	return it;
}

//将head设为当前位置
template
void Single_LList::moveToStart()
{
	curr = head;
}

//将tail设为当前位置
template
void Single_LList::moveToEnd()
{
	curr = tail;
}

//将当前位置左移一位,如果已在最前,无改变
template
void Single_LList::prev()
{
	if (curr == head)
	{
		return;
	}

	Node* temp = head;
	while (temp->next != curr)
	{
		temp = temp->next;
	}

	curr = temp;
}

//将当前位置右移一位,如果已在最后,无改变
template
void Single_LList::next()
{
	if (curr == tail)
	{
		return;
	}

	curr = curr->next;
}

//返回链表长度,即
template
int Single_LList::length() const
{
	return cnt;
}

//返回当前位置
template
int Single_LList::currPos() const
{
	Node* temp = head;
	int pos = 0;
	while (temp != curr)
	{
		pos++;
		temp = temp->next;
	}
	return pos;
}

//将当前位置设为指定位置
template
void Single_LList::moveToPos(int pos)
{
	Assert((pos >= 0) && (pos <= cnt), "设定位置越界");
	curr = head;
	for (int i = 0; i != pos; i++)
	{
		curr = curr->next;
	}
}

//返回当前位置的元素值
template
const E& Single_LList::getValue() const
{
	Assert(curr != tail, "无值可取");
	return curr->next->element; 
}


main.c 主函数,测试构造的单链表是否可用

/********************************************************/
// 主函数
// 用于测试编写的各函数与数据结构
/********************************************************/
#include "Public.h"
#include "Tools.h"
#include "SeqStack.h"
#include "SeqStack_Vector.h"
#include "SeqStack_VT_Def.h"
#include "postfix.h"
#include "ArrayBasedList_Def.h"
#include "Single_Linked_List_Def.h"

int main()
{
	/********************************************************/
	// 4,《数据结构与算法分析》Clifford 4.1.2单链表
	/********************************************************/
	Single_LList iSLList;

	iSLList.insert(1);
	iSLList.insert(2);
	iSLList.insert(3);
	iSLList.insert(4);
	cout << "after insert" << endl;
	iSLList.print();

	iSLList.clear();
	cout << "after clear" << endl;
	iSLList.print();
}

运行结果:

数据结构学习笔记4——单链表的实现_第3张图片



你可能感兴趣的:(学习笔记,数据结构)