数据结构(3)——线性表,最简单的数据结构

线性表是一种抽象数据类型,表示有限有序的值集合,允许重复值存在。与数组不同,线性表仅支持顺序访问。文章介绍了线性表的基本概念,包括如何创建线性表,判断是否为空,获取长度,查找元素以及插入元素等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

In computer science, a list or sequence is an abstract data type that implements a finite ordered collection of values, where the same value may occur more than once. An instance of a list is a computer representation of the mathematical concept of a finite sequence; the (potentially) infinite analog of a list is astream. Lists are a basic example of containers, as they contain other values. If the same value occurs multiple times, each occurrence is considered a distinct item. Lists are distinguished from arrays in that lists only allow sequential access, while arrays allow random access.

A singly linked list structure, implementing a list with 3 integer elements.

The name list is also used for several concrete data structures that can be used to implement abstract lists, especiallylinked lists.

摘录自维基百科,线性表List (abstract data type).
可见,线性表虽然简单,但它却是很多派生数据结构的基础(如右图,可以拓展成链表),而且还是a basic example of containers.正好练习c++,而且大一已经学过c语言的表示方法,再使用c语言表示除了复习一下以外也没什么意义,所以重新用c++表示并做测试,既复习也巩固练习c++.
首先,先实现最简单的、由数组表示的一个线性表对象实例,将得到的代码放入list.h这个头文件,方便进行后续的测试。
注意,这里实现的是一个线性表,而线性表和链表是有区别的。线性表示数据结构中最简单的一种数据结构,它是顺序存储的,通过数组实现;而链表在内存中是离散存储的,通过指针实现。对于一个线性表,我们有必要实现以下操作:
  • 创建一个线性表
  • 确定线性表是否为空
  • 确定线性表的长度
  • 查找第k个元素
  • 查找指定的元素
  • 在第k个元素之后插入一个新元素
#ifndef  LIST_H
#define LIST_H
#include<iostream>
using namespace std;
//定义list.h中的内容,即为数组表示的线性表。

//基于公式的类LinearList
template<class T>
class LinearList{
public:
	LinearList(int MaxListSize = 10);//构造函数
	~LinearList() {delete [] element;}//析构函数
	bool IsEmpty() const {return length == 0;}
	int Length() const {return length;}
	bool Find(int k,T& x) const;//返回第k个元素至x中
	int Search(const T& x) const;//返回x所在的位置
	LinearList<T>& Delete(int k,T& x);//删除第k个元素并将它返回至x中
	LinearList<T>& Insert(int k,const T&x);//在第k个元素之后插入x
	void Output(ostream& out) const;
private:
	int length;
	int MaxSize;
	T *element;//一维动态数组
};

//基本的表操作如下
template<class T>
LinearList<T>::LinearList(int MaxListSize){
	//基于公式的线性表的构造函数
	MaxSize = MaxListSize;
	element = new T[MaxSize];
	length=0;
}

template<class T>
bool LinearList<T>::Find(int k,T& x) const{
	//把第k个元素取至x中
	//如果不存在第k个元素则返回false,否则返回true
	if(k<1||k>length) return false;//不存在第k个元素
	x=element[k-1];
	return true;
}

template<class T>
int LinearList<T>::Search(const T& x) const{
	//查找x,如果找到,则返回x所在的位置
	//如果x不在表中,则返回0
	for(int i=0;i<length;i++)
		if(element[i]==x) return +++i;
	return 0;
}

template<class T>
LinearList<T>& LinearList<T>::Delete(int k, T& x){
	//把第k个元素放入x中,然后删除第k个元素
	//如果不存在第k个元素,则引发异常OutOfBounds
	if (Find(k, x)){//把元素k+1,...向前移动一个位置
		for (int i = k; i < length; i++)
			element[i - 1] = element[i];
		length--;
		return *this;
	}
	else throw OutOfBounds();
}

template<class T>
LinearList<T>& LinearList<T>::Insert(int k, const T& x){
	//在第k个元素之后插入x
	//如果不存在第k个元素,则引发异常OutOfBounds
	//如果表已经满,则引发异常NoMem();
	if (k<0 || k>length) throw OutOfBounds();
	if (length == MaxSize) throw NoMem();
	//插入元素,并将后面元素向后移动一位
	for (int i = length-1; i >k&&i==k; i++)
		element[i + 1] = element[i];
	element[k] = x;
	length++;
	return *this;
}

template<class T>
void LinearList<T>::Output(ostream& out) const{
	//把表送至输出流
	for (int i = 0; i < length; i++)
		out << element[i] << " ";
}
//重载操作符<<
template<class T>
ostream& operator<<(ostream& out, const LinearList<T>& x){
	x.Output(out);
	return out;
}

class OutOfBounds{
public:
	OutOfBounds() {}
};

//内存不足
//自己引发的异常NoMem
class NoMem{
public:
	NoMem(){}
};

//使new引发NoMem异常而不是xalloc异常
void my_new_handler(){
	throw NoMem();
}
new_handler Old_Handler_ =set_new_handler(my_new_handler);//调用函数set_new_handler,每当分配内存失败时,该函数就让操作符new调用函数my_new_handler()

#endif

接着,就可以写测试代码来对list.h进行测试(这并不是难点):
#include<iostream>
#include"list.h"
#include<conio.h>
using namespace std;
void main(void){
	try{
	LinearList<int>L(5);
	cout << "Length = " << L.Length() << endl;
	cout << "IsEmpty = " << L.IsEmpty() << endl;
	L.Insert(0, 2).Insert(1, 6);
	cout << "List is " << L << endl;
	cout << "IsEmpty = " << L.IsEmpty() << endl;
	int z;
	L.Find(1, z);
	cout << "First element is " << z << endl;
	cout << "Length = " << L.Length() << endl;
	L.Delete(1, z);
	cout << "Delete element is " << z << endl;
	cout << "List is " << L << endl;
}

catch (NoMem){
	cerr << "An exception has occurred" << endl;
	}
}
运行结果截图如下:
于是,线性表的测试完毕,代码完整无误。
但是,在接受一个线性表的公式化描述方法之前,先来考察一下这种描述方法的优缺点。的确,对于一个线性表的各种操作可以用非常简单的c++函数来实现。执行查找、删除和修改的函数都有一个最差的、与表的大小呈线性关系的时间复杂性。我们可能满足于这种复杂性。
这种描述方法的一大缺点就是空间的低效利用。如果我们需要三个表,而且知道三个表的总元素不超过5000个,但是有可能某个时刻某个表需要5000个元素,而另一时刻另一个表也需要5000个元素,这样就必须保证每个表的容量都是5000个元素,然后又必然有很多元素是空的。
于是,链表诞生了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值