线性表是最常用而且简单的一种数据结构,一个线性表是n个数据元素的有限序列。
当线性表需要频繁查找,较少插入和删除时,通常采用顺序存储结构,若需要频繁插入和删除,通常采用基于链表的形式;当线性表的元素个数变化较大或不确定时,最好用链表,这样不需要考虑存储空间大小问题,当事先知道线性表的大小长度,用顺序存储结构效率会高一些。
1、线性表的顺序表示和实现顺序表,基于数组的一种实现,一组地址连续的存储单元。顺序表可以是动态的,也可以是静态的,“静态”就是一开始就知道表容量,并且这个容量在之后无法被更改;“动态”就是能够动态的改变表的容量,实现上基于动态内存分配。数组大小有两种方式指定,一是静态分配,二是动态扩展。
优点:查找很方便
缺点:插入元素、删除元素比较麻烦,时间复杂度 O(n)
顺序表实现:
#include <iostream>
#include <cstdlib>
#include "assert.h"
const int MAXSIZE = 512;
template <class T>
class SeqList {
public:
SeqList() { length = 0; } //默认构造函数
SeqList(const T a[], int n); //含参构造函数
int GetLength() { return length; } //获取长度
void Insert(int i, T x); //插入元素
T Delete(int i); //删除元素
T Get(int i); //通过下标获取元素
int Locate(T x); //通过元素值查找元素
void Print(); //打印输出
private:
int length;
T data[MAXSIZE];
};
template <class T>
SeqList<T>::SeqList(const T a[], int n) {
if (n > MAXSIZE) {
throw "超过顺序表的最大长度";
}
for (int i = 0; i < n; i++) {
data[i] = a[i];
}
length = n;
}
template <class T>
void SeqList<T>::Insert(int i, T x) {
if (length > MAXSIZE) throw "上溢异常";
if (i<0 || i>length) throw "位置异常";
for (int j = length; j >= i; j--) {
data[j] = data[j - 1];
}
data[i] = x;
length++;
}
template <class T>
T SeqList<T>::Delete(int i) {
if (length == 0) throw "下溢异常";
if (i<0 || i>=length) {
throw "位置异常";
}
T x = data[i];
for (int j = i; j < length - 1; j++) {
data[j] = data[j + 1];
}
length--;
return x;
}
template <class T>
T SeqList<T>::Get(int i) {
if (0 == length) throw"上溢异常";
if (i<0 || i>=length) {
throw "查找位置非法";
}
return data[i];
}
template <class T>
int SeqList<T>::Locate(const T x) {
for (int i = 0; i < length; i++) {
if (x == data[i])
return i;
}
return 0;
}
template <class T>
void SeqList<T>::Print() {
cout << "遍历线性表数据元素:" << endl;
for (int i = 0; i < length; i++) {
cout << data[i] << " ";
}
cout << endl;
}
2、线性表的链式表示和实现
顺序表的链式表示形式又分为了:单链表、双向链表、单循环链表、双向循环链表几种。
优点:插入或删除元素时很方便,使用灵活,存储空间利用率高。
缺点:存储密度小(<1),查找和修改需要遍历整个链表。
单链表
代码实现:
#include <iostream>
#include <cstdlib>
#include "assert.h"
template <class T>
class LNode
{
public:
T data;
LNode<T>* next;
};
template <class T>
class LinkList {
public:
LinkList() { head = nullptr; }
~LinkList();
bool clear();
bool empty() { return head == nullptr; };
int length();
bool getElem(int i, T& t);
int locateElem(const T& t);
bool priorElem(const T& t_cur, T& t_pre);
bool nextElem(const T& t_cur, T& t_next);
bool insert(int i, T t);
bool term(int i, T t);
LNode<T>* reverse();
private:
LNode<T>* head;
};
//清空函数
template <class T>
bool LinkList<T>::clear() {
LNode<T> *p = head;
while (head) {
p = head;
head = head->next;
delete(p);
}
return true;
}
//析构函数
template <class T>
LinkList<T>::~LinkList() {
clear();
}
//获取链表长度
template <class T>
int LinkList<T>::length() {
LNode<T>* p = head; //不能直接用head循环
int len = 0;
while (p != nullptr) {
len++;
p = p->next;
}
return len;
}
//获取指定位置元素
template <class T>
bool LinkList<T>::getElem(int i, T &t) {
int j = 0;
LNode<T>* p = head;
while (j < i && p) {
p = p->next;
j++;
}
if (p == nullptr) return false;
t = p->data;
return true;
}
//查找元素位置
template <class T>
int LinkList<T>::locateElem(const T& t) {
int loc = 0;
LNode<T>* p = head;
while (p->data!=t && p) {
p = p->next;
loc++;
}
if (p->data == t) return loc;
else return -1;
}
//获取前驱节点
template <class T>
bool LinkList<T>::priorElem(const T& t_cur, T& t_pre) {
LNode<T>* p = head;
if (p->data == t_cur) return false;
while (p->next->data != t_cur && p->next) {
p = p->next;
}
if (p->next->data == t_cur) {
t_pre = p->data;
return true;
}
return false;
}
//获取后继节点
template <class T>
bool LinkList<T>::nextElem(const T& t_cur, T& t_next) {
LNode<T>* p = head;
if (head == nullptr || head->next == nullptr) return false;
while (p->next != nullptr) {
if (p->data == t_cur)
{
t_next = p->next->data;
return true;
}
else
p = p->next;
}
return false;
}
template <class T>
bool LinkList<T>::insert(int i, T t) {
LNode<T>* p = head;
LNode<T>* s = head;
int loc = 0;
if (i == 0) {
s = (LNode<T>*)malloc(sizeof(LNode<T>));
s->data = t;
s->next = p;
head = s;
return true;
}
while (p && loc < i - 1) {
p = p->next;
loc++;
}
if (p == nullptr)
return false;
s = (LNode<T>*)malloc(sizeof(LNode<T>));
s->data = t;
s->next = p->next;
p->next = s;
return true;
}
//删除指定位置元素
template <class T>
bool LinkList<T>::term(int i, T t) {
LNode<T>* p = head;
int loc = 0;
if (i == 0) {
t = head->data;
head = head->next;
delete p;
p = nullptr;
return true;
}
while (p && loc < i - 1) {
loc++;
p = p->next;
}
if (p == nullptr)
return false;
LNode* s;
s = p->next;
p->next = p->next->next;
t = s->data;
delete s;
s = NULL;
return true;
}
//反转链表
template <class T>
LNode<T>* LinkList<T>::reverse() {
if (head == nullptr || head->next == nullptr) return head;
LNode<T> *p = head, *q = head->next, *r;
head->next = nullptr;
while (q) {
r = q->next;
q->next = p;
p = q;
q = r;
}
head = p;
return head;
}
双向链表
代码实现:
#include <iostream>
#include <cstdlib>
#include "assert.h"
template <class T>
class DNode
{
public:
DNode<T> *next;
DNode<T> *prev;
T data;
};
template <class T>
class List
{
public:
List();//默认构造函数
List(const List& ln);//拷贝构造函数
~List();//析构函数
void add(T e);//向链表添加数据
void remove(T index);//移除某个结点
T find(int index);//查找结点
bool empty();//判断是否为空
int size();//链表长度
void print();//显示链表
void print_reverse();//链表反向显示
void clear();//删除全部结点
private:
DNode<T> *head;
DNode<T> *tail;
int length;
};
//默认构造函数
template <typename T>
List<T>::List()
{
head = new DNode<T>;
tail = new DNode<T>;
head->next = tail;
head->prev = nullptr;
tail->next = nullptr;
tail->prev = head;
length = 0;
}
//拷贝构造函数
template <typename T>
List<T>::List(const List &ln)
{
head = new DNode<T>;
head->prev = nullptr;
tail = new DNode<T>;
head->next = tail;
tail->prev = head;
length = 0;
DNode<T>* temp = ln.head;
while (temp->next != ln.tail)
{
temp = temp->next;
tail->data = temp->data;
DNode<T> *p = new DNode<T>;
p->prev = tail;
tail->next = p;
tail = p;
length++;
}
tail->next = nullptr;
}
//析构函数
template <typename T>
List<T>::~List()
{
if (length == 0)
{
delete head;
delete tail;
head = nullptr;
tail = nullptr;
return;
}
while (head->next != nullptr)
{
DNode<T> *temp = head;
head = head->next;
delete temp;
}
delete head;
head = nullptr;
}
//向链表添加数据
template <typename T>
void List<T>::add(T e)
{
DNode<T>* temp = this->tail;
tail->data = e;
tail->next = new DNode<T>;
DNode<T> *p = tail;
tail = tail->next;
tail->prev = p;
tail->next = nullptr;
length++;
}
//查找结点
template <typename T>
T List<T>::find(int index)
{
if (length == 0)
{
std::cout << "List is empty";
return NULL;
}
if (index >= length)
{
std::cout << "Out of bounds";
return NULL;
}
int x = 0;
DNode<T> *p;
p = head->next;
while (p->next != nullptr && x++ != index)
{
p = p->next;
}
return p->data;
}
//删除结点
template <typename T>
void List<T>::remove(T index)
{
if (length == 0)
{
std::cout << "List is empty";
return;
}
DNode<T> *p = head;
while (p->next != nullptr)
{
p = p->next;
if (p->data == index)
{
DNode<T> *temp = p->prev;
temp->next = p->next;
p->next->prev = temp;
delete p;
length--;
return;
}
}
}
//删除所有结点
template <typename T>
void List<T>::clear()
{
if (length == 0)
{
return;
}
DNode<T> *p = head->next;
while (p != tail)
{
DNode<T>* temp = p;
p = p->next;
delete temp;
}
head->next = tail;
tail->prev = head;
length = 0;
}
//判断是否为空
template <typename T>
bool List<T>::empty()
{
if (length == 0)
{
return true;
}
else {
return false;
}
}
//链表长度
template <typename T>
int List<T>::size()
{
return length;
}
//输出链表
template <typename T>
void List<T>::print()
{
if (length == 0)
{
std::cout << "List is empty" << std::endl;
return;
}
DNode<T> *p = head->next;
while (p != tail)
{
std::cout << p->data << " ";
p = p->next;
}
std::cout << std::endl;
}
//反向输出链表
template <typename T>
void List<T>::print_reverse()
{
if (length == 0)return;
DNode<T> *p = tail->prev;
while (p != head)
{
std::cout << p->data << " ";
p = p->prev;
}
std::cout << std::endl;
}
测试类main.cpp:
#include "CList.hpp"
#include <iostream>
using namespace std;
int main(int argc, char**argv)
{
cout << "***顺序表***" << endl;
SeqList<int> seqList;
int val = -1;
int iLocate = -1;
for (int i = 0; i < 10; i++)
{
seqList.Insert(i, i+1);
}
seqList.Print();
val = seqList.Get(3);
cout << "seqList.Get(3): " << val << endl;
val = seqList.Delete(2);
cout << "seqList.Delete(2): " << val << endl;
seqList.Print();
iLocate = seqList.Locate(5);
cout << "seqList.Locate(5): " << val << endl;
cout << endl;
cout << "***单链表***" << endl;
int a = 0;
int *p = &a;
LinkList<int> linkList;
linkList.insert(0, 5);
linkList.insert(1, 4);
linkList.insert(2, 12);
linkList.insert(3, 5);
linkList.insert(3, 6);
linkList.insert(1, 7);
cout << "链表长度" << linkList.length() << endl;
cout << "各个元素的值是: ";
for (int i = 0; i < linkList.length(); i++)//遍历该链表
{
if (linkList.getElem(i, *p))
cout << *p << " ";
}
cout << endl;
cout << "反转后各个元素的值是: ";
LNode<int>* re_linkList = linkList.reverse();
while (re_linkList)
{
cout << re_linkList->data << " ";
re_linkList = re_linkList->next;
}
cout << endl;
cout << endl;
cout << "***双向链表***" << endl;
List<int> list;
list.add(6);
list.add(443);
list.add(767);
list.add(56);
List<int> list2(list);
list2.print_reverse();
list2.print();
std::cout << "list2.size(): " << list2.size() << std::endl;
std::cout << "list2.find(2): " << list2.find(2) << std::endl;
list2.remove(443);
list2.print();
system("pause");
return 0;
}
执行结果:
--|END|--