线性表(1)——顺序表、单链表

1.顺序表

(1)顺序表的特点:

  •  

(2)顺序表与内置数组的区别:

  • 1)顺序表在数组的基础上封装了一些方便的操作
  • 2)顺序表的创建是在堆上申请内存,而传统的直接声明的数组是在栈上申请内存

(3)实现:

Line_Table_ADT.h

#pragma once              //有的编译器实现的保证.h文件只被编译一次,但要是写跨平台的程序,还是用ifndef,endif
#ifndef LINE_TABLE_ADT_H
#define LINE_TABLE_ADT_H

//抽象基类
template <typename T>
class List
{
public:
	typedef T  Element_Type;
	typedef T* Element_Pointer;
	typedef T& Element_Reference;
	typedef const T& Const_Element_Reference;
private:
	void operator= (const List&) {}
	List(const List&) {}
public:
	//构造函数
	List() {}
	//析构函数
	virtual ~List() {}

	//纯虚函数子类必须去继承它吗?
	//清空线性表
	virtual void clear() = 0;
	//在当前位置插入
	virtual void insert(Const_Element_Reference element) = 0;
	//在线性表末尾添加
	virtual void append(Const_Element_Reference element) = 0;
	//移除当前位置的元素
	virtual Element_Type remove() = 0;
	//当前位置的前一个元素
	virtual void prev() = 0;
	//当前位置的下一个元素
	virtual void next() = 0;
	//线性表的长度
	virtual int length() const = 0;
	//当前位置
	virtual int currPos() const = 0;
	//当前位置元素的值
	virtual Const_Element_Reference getValue() = 0;     //思考返回一个常引用有什么好处?
	//移动到指定位置
	virtual void moveToPosition(int position) = 0;
};
#endif

Array_List.h

#pragma once
//模板类的函数声明和定义应该放在同一个文件
#include "Line_Table_ADT.h"
#include <string>
#define ARRAY_DEFAULT_SIZE 100

using namespace std;

template <typename T>
class Array_List:public List<T>
{
public:
	//数据类型表
	typedef T  Value_Type;
	typedef Value_Type* List_Array;
	typedef const T& Const_Value_Reference;

private:
	int array_MaxSize;//顺序表可以存放元素的总空间  
	int list_Size;    //顺序表已有元素的长度
	int current_position;         //当前元素位置
	List_Array list_Array;//顺序表封装的数组

	//满足某种异常条件,抛出异常,打印错误信息
	void judge_OutOfRange(bool condition, const string& printInfo)
	{
		try
		{
			if (condition)
			{
				throw condition;
			}
		}
		catch (bool)
		{
			cerr << printInfo << endl;
			exit(1);
		}
	}

public:
	//默认构造函数
	Array_List(int size = ARRAY_DEFAULT_SIZE)
	{
		array_MaxSize = size;
		list_Size = current_position = 0;
		list_Array = new Value_Type[array_MaxSize];
	}
	//析构函数
	~Array_List()
	{
		delete[] list_Array;
	}

	//清空顺序表
	void clear() override
	{
		//先释放原先申请空间,再申请新的空间
		delete[] list_Array;
		list_Size = current_position = 0;
		list_Array = new Value_Type[array_MaxSize];
	}

	//插入
	void insert(Const_Value_Reference value) override
	{
		//插入之前判断数组是否已经满了
		judge_OutOfRange(list_Size >= array_MaxSize, "List capacity exceeded");
		//将当前位置及后续元素后移一位
		for (int i=current_position;i< list_Size;i++)
		{
			list_Array[i + 1] = list_Array[i];
		}
		//将值插入当前指针指向的位置
		list_Array[current_position] = value;
		list_Size++;     //关于前置和后置++操作效率问题?两个都能用的情况下应该用前置?
	}

	//末尾添加
	void append(Const_Value_Reference value) override
	{
		judge_OutOfRange(list_Size >= array_MaxSize, "List capacity exceeded");
		list_Array[list_Size] = value;
		list_Size++;
	}

	//删除
	Value_Type remove() override
	{
		judge_OutOfRange(list_Size <=0, "List capacity exceeded");

		Value_Type temp = list_Array[current_position];
		//直接将当前位置的元素均向前移动一位
		for (int i = current_position; i < list_Size-1; i++)
		{
			list_Array[i] = list_Array[i+1];
		}
		list_Size--;
		return temp;
	}

	//前一个元素
	void prev() override
	{
		judge_OutOfRange(current_position<=0, "Current Position is head of List!");
		current_position--;
	}

	//下一个元素
	void next() override
	{
		judge_OutOfRange(current_position >= list_Size, "Current Position is tail of List!");
		current_position++;
	}

	//线性表的长度
	int length() const override
	{
		return list_Size;
	}

	//线性表的当前位置
	int currPos() const override
	{
		return current_position;
	}

	//当前位置元素的值
	Const_Value_Reference getValue() const override
	{
		return list_Array[current_position];
	}

	//移动到指定位置
	void moveToPosition(int position) override
	{
		current_position = position;
	}
};

main.cpp

#include <iostream>
#include "Array_List.h"

using namespace std;

void print(Array_List<int>& array)
{
	array.moveToPosition(0);
	while(array.currPos() != array.length())
	{
		cout << array.getValue() << endl;
		array.next();
	}
	array.prev();
}

int main()
{
	Array_List<int> test_array_list;

	cout << "测试append函数" << endl;
	test_array_list.append(5);
	test_array_list.append(100);
	test_array_list.append(300);
	test_array_list.append(400);
	test_array_list.append(500);
	print(test_array_list);

	cout << "测试remove函数" << endl;
	cout << "被删除的元素的值为:" << test_array_list.remove() << endl;
	print(test_array_list);

	cout << "测试insert函数" << endl;
	test_array_list.moveToPosition(3);
	test_array_list.insert(25);
	print(test_array_list);

	cout << "测试prev、next、currPos" << endl;
	cout << "当前指针位置为:" << test_array_list.currPos() << endl;
	test_array_list.prev();
	test_array_list.prev();
	cout << "前移两次指针位置为:" << test_array_list.currPos() << endl;
	test_array_list.next();
	cout << "后移一次指针位置为:" << test_array_list.currPos() << endl;

	cout << "测试length" << endl;
	cout << "当前顺序表的长度为:" << test_array_list.length() << endl;

}

运行结果:

2.单链表

(2)实现

 

Single_Link_List.h

#pragma once
#include "Line_Table_ADT.h"
#include "Single_Link_List_Node.h"
#include <string>
#include <iostream>

template <typename T>
class Single_Link_List:public List<T>
{
public:
	typedef Single_Link_List_Node<T>  Node;
	typedef Single_Link_List_Node<T>* Head_Type;
	typedef Single_Link_List_Node<T>* Tail_Type;
	typedef Single_Link_List_Node<T>* Current_Type;
	typedef T Value_Type;
	typedef const T&  Const_Value_Reference;
private:
	Head_Type head;
	Tail_Type tail;
	Current_Type curr;
	int list_Length;

	//初始化的函数,只用于此类,不提供对外接口
	void init()
	{
		head = tail = curr = new Node;
		list_Length = 0;
	}

	void removeAll()
	{
		while (head != nullptr)
		{
			curr = head;
			head = head->next;
			delete curr;
		}
	}

	//满足某种异常条件,抛出异常,打印错误信息
	void judge_OutOfRange(bool condition, const std::string& printInfo)
	{
		try
		{
			if (condition)
			{
				throw condition;
			}
		}
		catch (bool)
		{
			std::cerr << printInfo << std::endl;   //为什么不要在.h文件中使用using namespace std?
			exit(1);
		}
	}
public:
	Single_Link_List()
	{
		init();
	}
	~Single_Link_List()     //这里析构函数其实还是虚函数,因为它的父类是
	{
		removeAll();
	}

	void clear() override
	{
		removeAll();
		init();
	}

	//默认删除和插入操作都是对当前结点的下一个结点操作,这样写方便操作
	void insert(Const_Value_Reference value) override
	{
		Node* temp = curr->next;
		curr->next = new Node;			//使用operator new分配内存
		::new(curr->next)Node(value,temp);
		if (curr == tail)				//记得判断尾节点的特殊情况
			tail = curr->next;
		list_Length++;
	}

	void append(Const_Value_Reference value) override
	{
		tail->next = new Node(value, nullptr);
		tail = tail->next;			
		list_Length++;
	}

	Value_Type remove() override
	{
		//判断链表是否为空
		judge_OutOfRange((curr->next == nullptr), "Link_List is none!");

		Value_Type remove_value = curr->next->value;

		//移除一个结点:让当前结点的下一个结点的指针,指向下一个结点的下一个结点,同时释放当前下一个结点
		Node* temp = curr->next;
		if (tail == curr->next)
			tail = curr;
		curr->next = curr->next->next;
		delete  temp;  
		list_Length--;
		
		return remove_value;
	}

	void prev() override
	{
		if (curr == head)
			return;
		Node* temp=head;
		while (temp->next != curr)
			temp = temp->next;
		curr = temp;
	}

	void next() override
	{
		if (curr != tail)
			curr = curr->next;
	}

	int length() const
	{
		return list_Length;
	}

	Const_Value_Reference getValue()  override
	{
		//判断链表是否为空
		judge_OutOfRange((curr->next == nullptr), "Link_List is none!");

		return curr->next->value;
	}

	int currPos()const override
	{
		Node* temp = head;
		int i;
		for (i = 0; temp != curr; i++)
		{
			temp = temp->next;
		}
		return i;
	}

	void moveToPosition(int position) override
	{
		judge_OutOfRange((position<0 || position>=list_Length),"Position is out of range!");
		curr = head;
		for (int i = 0; i < position; i++)
			curr = curr->next;
	}

    	//遍历打印
	void print()
	{
		for (int i = 0; i < length(); i++)
		{
			moveToPosition(i);
			std::cout << getValue() << std::endl;
		}
	}

};

main.cpp

#include <iostream>
#include "Single_Link_List.h"

using namespace std;

int main()
{
	Single_Link_List<int> test_link_list;

	cout << "测试insert和append函数" << endl;
	test_link_list.insert(5);
	test_link_list.insert(100);
	test_link_list.insert(300);
	test_link_list.append(400);
	test_link_list.append(500);
	test_link_list.print();

	cout << "\n测试remove函数" << endl;
	cout << "被删除的元素的值为:" << test_link_list.remove() << endl;
	test_link_list.print();


	cout << "\n测试prev、next、currPos" << endl;
	cout << "当前指针位置为:" << test_link_list.currPos() << endl;
	test_link_list.prev();
	test_link_list.prev();
	cout << "前移两次指针位置为:" << test_link_list.currPos() << endl;
	test_link_list.next();
	cout << "后移一次指针位置为:" << test_link_list.currPos() << endl;

	cout << "\n测试length" << endl;
	cout << "当前顺序表的长度为:" << test_link_list.length() << endl;

	cout << "\n测试clear" << endl;
	test_link_list.clear();
	cout << "当前顺序表的长度为:" << test_link_list.length() << endl;
	test_link_list.append(500);
	cout << "当前顺序表的长度为:" << test_link_list.length() << endl;
	test_link_list.print();
}

运行结果:

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值