大师兄的数据结构学习笔记(二):线性结构
一、 线性表
1. 什么是线性表
- 线性表是n个具有相同特性的数据元素的有限序列。
- 表中元素个数成为线性表的长度。
- 长度为0时,成为空表。
- 表的起始位置称表头,结束位置称表尾。
2. 线性表的抽象数据类型描述
- 类型名称:线性表(list)
- 数据对象集: 线性表是个元素构成的有序序列(
- 操作集:线性表,整数i表示位置,元素
- 主要操作有:
操作 含义 SeqList() 无参数构造方法 SeqList(DataType a[], int n) 有参数构造方法 ~SeqList() {} 析构函数 int Length() 获取长度 DataType Find(int i) 查找值 int Locate(DataType x) 查找位置 void Insert(int DataType x) 插入元素 DataType Delete(int i) 删除元素 void PrintList() 遍历线性表
3. 线性表存储方式
3.1 顺序存储
-
利用数组的连续存储空间,顺序存放线性表的各元素。
- 优点:
序号 | 优点 |
---|---|
1 | 随机访问特性,查找O(1)时间,存储密度高。 |
2 | 逻辑上相邻的元素,物理上也相邻。 |
3 | 无须为表中元素之间的逻辑关系而增加额外的存储空间。 |
- 缺点:
序号 | 缺点 |
---|---|
1 | 插入和删除需移动大量元素。 |
2 | 当线性表长度变化较大时,难以确定存储空间的容量。 |
3 | 造成存储空间的“碎片”。 |
- 代码实现:
#ifndef SEQLIST_H
#define SEQLIST_H
const int MaxSize = 100;
template
class SeqList
{
public:
SeqList() { length = 0; } //无参数构造方法
SeqList(DataType a[], int n); //有参数构造方法
~SeqList() {}; //析构函数
int Length() { return length; } //获取长度
DataType Find(int i); //查找值
int Locate(DataType x); //查找位置
void Insert(int i, DataType x); //插入元素
DataType Delete(int i); //删除元素
void PrintList(); //遍历线性表
private:
DataType data[MaxSize];
int length;
};
#endif
#include "seqlist.h"
#include
using namespace std;
template
SeqList::SeqList(DataType a[], int n)
{
//有参数构造方法
if (n > MaxSize) throw "Parameter Over MaxSize";
for (int i = 0; i < n; i++)
data[i] = a[i];
length = n;
}
template
DataType SeqList::Find(int i)
{
//按位查找
if (i<1 && i>length) throw "Location Over Size";
else return data[i - 1];
}
template
int SeqList::Locate(DataType x)
{
//按值查找
for (int i = 0; i < length; i++)
if (data[i] == x) return i + 1;
return 0;
}
template
void SeqList::Insert(int i, DataType x)
{
//插入元素
if (length >= MaxSize) throw "Overflow";
if (i<1 || i>length + 1) throw "Location";
for (int j = length + 1; j > i; j--)
data[j] = data[j - 1];
data[i - 1] = x;
length++;
}
template
DataType SeqList::Delete(int i)
{
//删除元素
int x;
if (length == 0) throw "Underflow";
if (i<1 || i>length) throw "Location";
x = data[i - 1];
for (int j = i; j < length; j++)
data[j - 1] = data[j];
length--;
return x;
}
template
void SeqList::PrintList()
{
//遍历线性表
for (int i = 0; i < length; i++)
cout << data[i] << endl;
}
3.2 链式存储
- 不要求逻辑上相邻的两个元素物理上也相邻。
- 通过"链"建立起数据元素之间的逻辑关系。
- 插入删除不需要移动数据元素,只需要修改“链”。
- 优点:
序号 | 优点 |
---|---|
1 | 插入、删除不需移动其他元素,只需改变指针。 |
2 | 链表各个节点在内存中空间不要求连续,空间利用率高。 |
- 缺点:
序号 | 缺点 |
---|---|
1 | 查找需要遍历操作,比较麻烦。 |
- 代码实现:
#ifndef SEQCHAIN_H
#define SEQCHAIN_H
template
struct Node
{
//存储结构
DataType data; //数据
Node* next; //下一个节点的地址
};
template
class SeqList
{
public:
SeqList(); //无参数构造方法
SeqList(DataType a[], int n); //有参数构造方法
~SeqList(); //析构函数
int Length(); //获取长度
DataType Find(int i); //查找值
int Locate(DataType x); //查找位置
void Insert(int i, DataType x); //插入元素
DataType Delete(int i); //删除元素
void PrintList(); //遍历线性表
private:
Node* first;
};
#endif
#include "seqlist.h"
#include
using namespace std;
template
SeqList::SeqList()
{
//无参数构造方法
first = new Node;
first->next = nullptr;
}
template
SeqList::SeqList(DataType a[], int n)
{
//有参数构造方法
first = new Node;
first->next = nullptr;
for (int i = 0; i < n; i++)
{
Node* s = new Node;
s->data = a[i];
s->next = first->next;
first->next = s;
}
}
template
SeqList::~SeqList()
{
//析构函数
while (first != nullptr)
{
Node* q = first;
first = first->next;
delete q;
}
}
template
int SeqList::Length()
{
//获取长度
Node* p = first->next;
int count = 0;
while(p != nullptr)
{
p = p->next;
count++;
}
return count;
}
template
DataType SeqList::Find(int i)
{
//查找值
Node* p = first->next;
int count = 1;
while (p != nullptr && count < i)
{
p = p->next;
count++;
}
if (p == nullptr) throw "Location";
else return p->data;
}
template
int SeqList::Locate(DataType x)
{
//查找位置
Node* p = first->next;
int count = 1;
while (p != nullptr)
{
if (p->data == x) return count;
count++;
}
return 0;
}
template
void SeqList::Insert(int i, DataType x)
{
//插入元素
Node* p = first;
int count = 0;
while (p != nullptr && count < i - 1)
{
p = p->next;
count++;
}
if (p == nullptr) throw "Location";
else {
Node* s = new Node;
s->data = x;
s->next = p->next;
p->next = s;
}
}
template
DataType SeqList::Delete(int i)
{
//删除元素
Node* p = first;
int count = 0;
while (p != nullptr && count < i - 1)
{
p = p->next;
count++;
}
if (p == nullptr || p->next == nullptr) throw "Location";
else {
Node* q = p->next;
int x = q->data;
p->next = q->next;
return x;
}
}
template
void SeqList::PrintList()
{
//遍历线性表
Node* p = first->next;
while (p != nullptr)
{
cout << p->data << endl;
p = p->next;
}
}
4. 其他线性表
4.1 广义表
- 是线性表的推广。
-
在线性表中,元素是基本的原元素,而在广义表中,元素不仅可以是元素,也可以是另一个广义表。
- 实现数据结构:
enum elem_tag
{
DATA, LIST
};
class GLnode
{
private:
elem_tag Tag; // 0:元素节点 1:子表
union
{
char data; // 元素节点的值域
struct // 表节点
{
GLnode* hp;
GLnode* tp;
}ptr;
};
};
4.2 多重链表
-
链表中的节点可能同时隶属于多个链。
- 多重链表中节点的指针域会有多个, 但包含两个指针域的链表并不一定是多重链表。
- 经常用于树、图等复杂数据结构。
- 以实现双链表存储方法结构为例:
template
struct Node
{
DataType data;
Node* prior, * next;
};
参考资料
- https://blog.csdn.net/qq_30611601/article/details/79516986 Quanfita
本文作者:大师兄(superkmi)