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();
}
运行结果: