【自留】数据结构之线性表

本文详细介绍了线性表的概念、顺序存储结构(包括静态和动态分配)、单链表和双链表的构造与操作,包括构造函数、析构函数、判空、遍历、查找、插入和删除等方法。
摘要由CSDN通过智能技术生成
  • 线性表:n个数据元素的有限序列,表中数据元素个数被称为线性表的长度,长度为0则是空表

    【抽象性】【(类型)相同性】【有限性】

  • 任意相邻元素之间存在序偶关系,即前驱与后继。

顺序表【静态存储分配&动态存储分配】
  1. 线性表的顺序存储结构:用一段地址连续的存储单位依次存储线性表的数据元素。
  2. 计算任意一个元素的存储地址的时间是相等的,具该特点的存储结构为随机存取
  3. 用一维数组实现顺序表->必须确定存放线性表的数组空间的长度。
构造顺序表
  • 模板类定义 使用2个参数ver
template <typename T>
class SeqList{
	private::
	T  data[100];
	int length;
}
或者
private:
	T *elem;  //存储空间基址
	int length;
  • 构造函数
template <typename T>
SeqList<T>::SeqList(T a[],int n){
	if(n>100)throw "参数非法";
	for(int i=0;i<n;i++){
	data[i]=a[i];
	}
	length=n;
}
或者
{
	this->elem=(T *)malloc(sizeof(T)*n);
	if(!this->elem)throw "参数非法";
	this->length=n;
}
  • 析构函数:

    对于第一种:**静态存储分配,**顺序表变量退出作用域时自动释放该变量占用的内存空间,故无需销毁,析构函数为空

    第二种:

    free(this->elem);
    this->elem=nullptr;
    this->length=0;
    
  • 判空函数

    看length是否为0

  • 遍历函数

template <typename T>
vpid SeqList<T>::PrintList(){
	for(int i=0;i<length;i++){
	cout<<data[i]<<"  ";
	}
	cout<<endl;
}
或者
void SeqList<T>::printList(void (*print)(T &elem))
{
for(int i=0;i<this->length;i++)
	print((this->elem)[i]);
cout<<endl;
}
  • 查找函数

第一种按位置寻找看下标,按值寻找遍历;

第二种同理

  • 插入函数
因为表定义长度为100,所以有可能有空余位置,有则把插入元素后的元素后移
template <typename T>
void SeqList<T>::Insert(int i,T x){
	if(length==100)thorw"上溢";
	if(i<1||i>length+1)throw"插入位置错误";
	for(int j=length;j>=i;j--){
		data[j]=data[j-1];
	}
	data[i-1]=x;
	length++;
}
或者
{
if(this->length==100){
	T *newelem=(T *)realloc(this->elem,(this->length+1)*sizeof(T));
	if(!newelem)throws "Error allocating memory!"<<endl;
}
//像上面那样根据情况赋值
for(int j=this->length;j>=i;j--){
(this->elem)[j]=(this->elem)[j-1];
}
(this->elem)[i-1]=elem;
this->length+=1;
}
  • 删除函数

第一种把插入反过来

//throws 1.length=0 2.i<1||i>length
elem=(this->elem)[i-1];
for(int j=i-1;j<this->length-1;j++){
(this->elem)[j]=(this->elem)[j+1];
}
this->length-=1;
单链表
  1. 为何设立头结点:无论单链表是否为空,头指针始终指向头结点,统一空表和非空表的处理。
构造单链表
  • 结点定义
template <typename T>
struct Node{
	T data;
	Node<T> *next;
}
class LinkList{
private:
	Node<T>*first;
}
  • 构造函数

    1. 初始化——无参构造

      template <typename T>
      LinkList<T>::LinkList(){
      	first7=new Node<T>; //生成头结点
      	irst->next=nullptr; //头结点
      }
      
    2. 头插法:把申请的结点插在头结点后面

      LinkList<T>::LinkList(T a[],int n){
      	first=new Node<T>;
      	first->next=nullptr;
      	for(int i=0;i<n;i++){
      	s=new Node<T>;
      	s->data=a[i];
      	//把s插入到头结点后面
      	s->next=first->next;
      	first->next=s;
      	}
      }
      
    3. 尾插法:把申请的结点插在终端结点后面,故设立尾指针指向当前的终端结点

      {
      	first=new Node<T>;
      	Node<T>*r=first,*s=nullptr;
      	for(int i=0;i<n;i++){
      		s=new Node<T>;
      		s->data=a[i];
      		r->next=s;
      		r=s;
      	}
      	r->next=nullptr;
      }
      
  • 判空函数

    判断单链表是否只有头结点==first->next是否为空

  • 遍历函数

    ⭐工作指针p后移不能写成p++:存储单元可能不连续,p++不能一定保证p指向下一个结点。

template <typename T>
void LinkList<T>::PrintList(){
	//工作指针p初始化
	Node<T>*p=first->next;
	while(p!=nullptr){
		cout<<p->data<<"\t";
		p=p->next;
	}
	cout<<endl;
}
  • 求长函数

    结合遍历函数。

  • 寻找函数

    按值寻找与按位均是遍历

    //按位置:
    if(p==nullptr)throw "position wrong";
    

    按位寻找时间复杂度O(n),所以为顺序存取结构

  • 插入函数

    时间花费在查找正确插入位置,故复杂度为O(n)

{
	Node<T>*p=first->next;
	int count=0;
	while(p!=nullptr&&count<i-1){
		p=p->next;
		count+=1;
	}
	if(p==nullptr)throws "wrong position"
	else{
		s=new Node<T>;
		s->data=x;
		//把s插入到p后面
		s->next=p->next;
		p->next=s;
	}
}
  • 删除函数

    删除第i个结点:前驱节点p存在且p不为终端结点

    (int i)
    {
    	T x;
    	Node<T> *p=first,*q = nullptr;
    	int count=0;
    	//找第i-1个结点
    	if(p==nullptr||p->next==nullptr)throws "wrong position" //p不存在或p后继结点不存在
    	else{
    		q=p->next;
    		x=q->data;
    		p->next=q->next;
    		delete q;//把q摘下来
    		rertun x;//返回q的值
    	}
    }
    
  • 析构函数

    由于动态申请,故需要释放单链表的空间

    重复操作first=first->next;delete p;p=first;
    
双链表

可以快速确定单链表中任意结点的前驱结点

  • 插入操作-修改四个指针
p后面插入s
s->prior=p;
s->next=p->next;
p->next->prior=s;
p->next=s;
  • 删除操作-吞掉中间的结点
删除p
p->prior->next=p->next;
p->next->prior=p->prior;
循环链表-头尾相接

没有明显尾端,可能死循环:判断用作循环变量的工作指针是否等于头指针/尾指针/……(p!=first)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值