线性表——知识点


#include<iostream>
#include<iomanip>
#include<cmath>
#include<string.h>
#include<string>
#include <ctime>
#include<cstdlib>
#include<algorithm>
#include<cstdio>
#include<queue>
using namespace std;

//线性表知识点
// 定义:具有相同数据类型的n个数据元素的有限序列
// 特点:1.元素个数有限 2.有逻辑顺序 3.数据元素相同 

// 线性表基本操作:初始化,长度,增删查,打印,销毁
// InitList(&L)
// Length(L)
// LocateElem(L,e)
// GetElem(L,i)
// ListInsert(&L,i,e)
// ListDelete(&L,i,&e)
// PrintList(L)
// Empty(L)
// DestoryList(L)

// 顺序表:逻辑顺序和物理顺序相同

// 实现:本质就是数组
#define MaxSize 10
typedef struct //静态分配
{
    int data[MaxSize];//可以是任意类型表示元素
    int length;//表示当前长度
}SqList;
 
//初始化
void InitList(SqList &L)
{
    for(int i =0;i<MaxSize;i++)cin>>L.data[i];
    L.length = 0;
}

//动态分配
typedef struct //静态分配
{
    int *data;//可以是任意类型表示元素
    int Max;//最大长度
    int length;//表示当前长度
}SqList;

//初始化
void InitList(SqList &L)
{
    L.data = new int [MaxSize];
    L.length = 0;
    L.Max = MaxSize;
}

//增加动态数组长度
void IncreaseSize(SqList &L,int add_len)
{
    int *p = L.data;//记住原本的地址
    L.data = new int[L.Max+add_len];//开辟总长度
    for(int i =0;i<L.Max;i++) L.data[i] = p[i];//移植原本的数据
    L.Max+=add_len;//更新max
    delete []p;//释放原本的空间
}

//顺序表特点:
// 1.随机访问:可以再o(1)找到第i个元素
// 2.存储密度高,每个节点只存储数据元素并没有存下一个节点位置(不需要)
// 3.拓展容量不方便,只能使用动态
// 4.插入和删除不方便


//插入元素(平均为o(n))
bool ListInsert(SqList &L,int i,int e)//位置和元素
{
    if(i<1||i>L.length+1)return false;
    if(L.length>=MaxSize)return false;//装满了
    for(int j = L.Max;j>=i;j--)L.data[j] = L.data[j-1];//第i-1个元素后面的数字后移,可以理解为从第i+1个数字开始获得前面的值
    L.data[i-1] = e;
    L.length++;
    return true;
}

//删除操作平均为o(n)
bool ListDelete(SqList &L,int i,int &e)//位置和返回元素值
{
    if(i<1||i>L.length)return false;
    e = L.data[i-1];//记录删除元素
    for(int k =i-1;k<L.length-1;k++)L.data[k] = L.data[k+1];//从i位置前移
    L.length--;
    return true;
}

//按位查找o(1)
int GetElem(SqList L,int i)//位置
{
    return L.data[i-1];
}

//按值查找o(n)
int LocateElem(SqList L,int e)//值->返回位置
{
    for(int i =0;i<L.length;i++)
    {
        if(L.data[i]==e)return i+1;//返回位置
    }
    return 0;//表示没有找到
}

//链表
// 定义:节点包含数据元素和指向下一个节点的指针
// 定义
typedef struct LNode
{
    int data;
    LNode* next;
}LNode,*LinkList;//一个是结构体,一个是指向结构体的指针(就是链表)

//初始化不带头节点
bool InitList(LinkList &L)//没有开辟空间
{
    L = NULL;//防止野指针
    return true;
}
//判断单链表是否为空
bool Empty(LinkList &L)
{
    if(L==NULL)return true;
    else return false;
}

//初始化带头节点
bool InitList(LinkList &L)
{
    L = new LNode;//开辟空间
    if(L==NULL)return false;//内存不够
    L->next = NULL;
    return true;
}

//判断单链表是否为空
bool Empty(LinkList &L)
{
    if(L->next==NULL)return true;
    else return false;
}


//头指针和头节点的区别:
// 1.头指针都指向第一个节点
// 2.有头结点是第一个节点,通常不存储数据元素
// 大多数情况都使用带头节点不然会更麻烦

//单链表插入
//带头结点
bool ListInsert(LinkList &L,int i,int e)//位序和值
{
    if(i<1)return false;
    //扫描找到前面一个的位置
    LNode* p;
    int j =0;
    p = L;//从头节点0开始找
    while(p!=NULL&&j<i-1)//找到i-1个节点
    {
        j++;
        p = p->next;
    }
    if(p==NULL)return false;//不合法
    LNode*s = new LNode;//开辟一个空间
    s->next = p->next;
    p->next = s;//将s连接到p后
    s->data = e;
    return true;
}

//不带头节点(考虑特殊位置1,剩下和带头的相同)
bool ListInsert(LinkList &L,int i,int e)//位序和值
{
    if(i<1)return false;
    //扫描找到前面一个的位置

    if(i==1)
    {
        LNode*s  =new LNode;//开辟空间
        s->next = L;
        L = s;//这两步不一样
        s->data = e;
        return true;
    }
    LNode* p;
    int j =0;
    p = L;//从头节点0开始找
    while(p!=NULL&&j<i-1)//找到i-1个节点
    {
        j++;
        p = p->next;
    }
    if(p==NULL)return false;//不合法
    LNode*s = new LNode;//开辟一个空间
    s->next = p->next;
    p->next = s;//将s连接到p后
    s->data = e;
    return true;
}

//后插函数
bool InsertNextNode(LNode *p,int e)//p节点后面插入e
{
    if(p==NULL)return false;
    LNode*s = new LNode;//开辟空间
    if(s==NULL)return false;
    s->next = p->next;
    s->data = e;
    p->next = s;
    return true;
}

//前插函数
// 有头指针o(n)
bool InsertPriorNode(LinkList &L,LNode *p,int e)
{
    //找到p前一个节点
    LNode *ptr = L;
    while(ptr->next!=p&&ptr!=NULL)
    {
        ptr = ptr->next;
    }
    if(ptr==NULL)return false;
    LNode *s = new LNode;//开辟空间
    if(s==NULL)return false;

    s->next = ptr->next;
    s->data = e;
    ptr->next = s;
    return true;
}

//没有头节点o(1)
bool InsertPriorNode(LNode *p,int e)
{
    if(p==NULL)return false;
    LNode *s = new LNode;
    if(s==NULL)return false;
    //先后插入
    s->next = p->next;
    p->next = s;
    //交换数据
    s->data = p->data;
    p->data = e;
    return true;
}

//按位删除o(n)
//带头结点
bool ListDelete(LinkList &L,int i,int &e)//头指针,位序,删除值
{
    if(i<1)return false;
    //找到前一个节点
    int j =0;
    LNode *p = L;
    while (p!=NULL&&j<i-1)
    {
        j++;
        p = p->next;
    }
    if(p==NULL)return false;
    if(p->next==NULL)return false;//没有该节点
    //删除
    LNode *q = p->next;//i节点
    p->next = q->next;
    e = q->data;
    delete q;//释放空间
}
//不带头节点(特殊考虑i=1)
bool ListDelete(LinkList &L,int i,int &e)//头指针,位序,删除值
{
    if(i<1)return false;
    if(i==1)
    {
        if(L==NULL)return false;
        //记录第一个节点
        LNode *q = L;
        e = q->data;//记录值
        L = L->next;//舍弃掉第一个节点
        delete q;//释放空间
        return true;
    }
    //找到前一个节点
    int j =0;
    LNode *p = L;
    while (p!=NULL&&j<i-1)
    {
        j++;
        p = p->next;
    }
    if(p==NULL)return false;
    if(p->next==NULL)return false;//没有该节点
    //删除
    LNode *q = p->next;//i节点
    p->next = q->next;
    e = q->data;
    delete q;//释放空间
    return true;
}

//指定节点删除
// 带头结点,选择o(1)算法,有最后一个的缺陷
bool DeleteNode(LNode *p)
{
    if(p==NULL)return false;
    LNode *q = p->next;//后面一个节点
    p->data = q->data;//复制元素
    delete q;//释放空间
    return true;
}


//按位查找
LNode *GetElem(LinkList &L,int i)
{
    if(i<1)return NULL;//判断
    int j =0;
    LNode *p = L;
    while(p!=NULL&&j<i)//获得i节点
    {
        j++;
        p = p->next;
    }
    return p;
}

//封装后
// 按位插入
bool ListInsert(LinkList &L,int i,int e)
{
    if(i<1)return false;
    LNode *p = GetElem(L,i-1);//获得前面节点
    return InsertNextNode(p,e);//向后插入
}

//按值查找
LNode *GetElem(LinkList &L,int e)
{
    LNode*p = L;
    while (p!=NULL)
    {
        if(p->data==e)return p;
        p = p->next;
    }
    
}

//求表的长度
// 带头结点
int Length(LinkList L)
{
    int j =0;//统计长度
    LNode *p = L;
    while(p->next!=NULL)
    {
        j++;
        p = p->next;
    }
    return j;
}
//不带头结点
int Length(LinkList L)
{
    int j =1;
    LNode *p = L;
    if(p==NULL)return 0;
    while(p->next!=NULL)
    {
        j++;
        p = p->next;
    }
    return j;
}

//单链表的建立

//尾插法
LinkList List_TailInsert(LinkList &L)
{
    int x;//数据
    L = new LNode;//建立头结点
    LNode *s,*r =L;
    cin>>x;
    while(x!=9999)//9999表示结束
    {
        s = new LNode;//开辟空间
        s->data = x;//载入数据
        r->next = s;//确立连接
        r = s;//移动r
        cin>>x;
    }
    r->next = NULL;//尾结点置空
    return L;
}

//头插法
LinkList List_TailInsert(LinkList &L)
{
    int x;
    L = new LNode;
    L->next = NULL;//首节点置空
    LNode *s;//新节点
    while(x!=9999)
    {
        s = new LNode;
        s->data = x;
        s->next = L->next;
        L->next = s;
        cin>>x;
    }
    return L;
}

//双链表
//结点类型
typedef struct DNode
{
    int data;
    DNode *prior,*next;// 前后驱指针
}DNode,*DLinklist;

//初始化
bool InitDLinkList(DLinklist &L)
{
    L = new DNode;//开辟一个空间
    if(L==NULL)return false;
    L->next = NULL;
    L->prior = NULL;
    return true;
}

//插入
bool InsertNextNode(DNode *p,DNode *s)//在p结点后面插入s结点
{
    if(p==NULL||s==NULL)return false;
    s->next = p->next;
    if(p->next!=NULL)p->next->prior = s;
    p->next = s;
    s->prior = p;
}

//删除
bool DeleteNode(DNode *p)
{
    if(p==NULL)return false;
    DNode*q = p->prior;//获得前面结点
    DNode*r = p->next;//获得后面结点
    q->next = r;
    if(r!=NULL)r->prior = q;
    delete p;
    return true;
}

//循环单链表
//初始化
bool InitDLinkList(LinkList &L)
{
    L = new LNode;//开辟空间
    if(L==NULL)return false;
    L->next = L;
    return true;
}

//静态链表
//可以理解为结构体数组
//结构体存放数据和下一个数据的下标
struct  Node
{
    int data;
    int next;//下一个数组的下标
}SLinkList[MaxSize];

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值