数据结构笔记二——线性表

注:仅供个人学习使用,来源于wangdao考研和《数据结构(严蔚敏)》,侵权必删

目录

一.顺序表的定义

1.顺序表的静态定义

2.顺序表的动态定义

注:结构体相等的比较

二、单链表

1.单链表的定义

2.单链表的插入和删除操作

3.单链表的按位序查找和按值查找

4.单链表的建立

三、双链表

四、循环链表

五、静态链表


一.顺序表的定义

1.顺序表的静态定义

#include <stdio.h>
#define MaxSize 10  //定义最大长度 
//顺序表静态定义和初始化 
typedef struct{
    int data[MaxSize];  //用静态的“数组”存放数据元素 
    int length;  //顺序表当前的长度 
}SqList;  //顺序表的类型定义 

//基本操作——初始化一个顺序表
void InitList(SqList &L){
    for(int i=0;i<MaxSize;i++)
        L.data[i]=0;  //将所有元素设置为默认初始值
    L.length=0; 
} 

int main(){
    SqList L;  //声明一个顺序表 
    InitList(L);  //初始化顺序表
    //...
    return 0; 
    
}

2.顺序表的动态定义

#include <stdio.h>
#include <stdlib.h> 
//顺序表的定义和基本操作(动态) 
#define InitSize 10  //定义最大长度 
typedef struct{
    int *data;  //指示动态分配数组的指针 
    int MazSize;  //顺序表的最大容量 
    int length;  //顺序表当前的长度 
}SqList;  //顺序表的类型定义 

//基本操作——初始化一个顺序表

void InitList(SqList &L){
    //用malloc函数申请一片连续的存储空间 
    L.data=(int *)malloc(InitSize*sizeof(int)); 
    L.length=0; 
    L.MazSize-InitSize;
} 

//增加动态数组的长度
void IncreaseSize(SeqList &L, int len){
    int *p=L.data;
    L.data=(int *)malloc((L.MaxSize+len)*sizeof(int));
    for(int i=0;i<L.length;i++){
        L.data[i]=p[i];  //将数据复制到新区域 
    } 
    L.MaxSize=L.MaxSize+len;  //顺序表最大长度增加len 
    free(p);   //释放原来的内存空间 
} 
 
int main(){
    SqList L;  //声明一个顺序表 
    InitList(L);  //初始化顺序表
    //...往顺序表中随便插入几个元素。。
    IncreaseSize(L,5); 
    return 0; 
    
}

注:结构体相等的比较

#include<iostream>
using namespace std;
//结构体的相等“=”的比较 
typedef struct{
    int num;
    int people;
}Customer;

void test(){
    Customer a;
    a.num=1;
    a.people=1;
    Customer b;
    b.num=1;
    b.people=1;
/*    if(a==b){
//        printf("相等"); 
//    }
//    else{
//        printf("不相等");
    } */
}
bool isCustomerEqual(Customer a,Customer b){
    if(a.num==b.num&&a.people==b.people)
        return true;
    else
        return false; 
}
#C语言中,结构体的比较不能直接用“==”
#C++中可以使用重载运算符
#考研初试的时候,手写代码可以直接使用“==”,无论ElemType是否是结构体类型 

二、单链表

1.单链表的定义

//单链表的定义 

typedef struct LNode{  //定义单链表结点类型 
    ElemType data;  //数据域,每个结点存放一个数据元素 
    struct LNode *next;  //指针域,指针指向下一个结点 
}LNode, *LinkList; 

//不带头结点的单链表
//初始化一个空的单链表
bool InitList(LinkList &L){
    l=NULL;  //空表,暂时还没有任何结点,防止脏数据 
    return true; 
} 

//带头结点的单链表
//初始化一个单链表
bool InitList(LinkList &L){
    L=(LNode *)malloc(sizeof(LNode));  //分配一个头结点
    if(L==NULL)  //内存不足,分配失败 
        return false;
    L->next=NULL;  //头结点之后暂时还没有结点 
    return true; 
} 

void test(){
    LinkList L;  //声明一个指向单链表的指针 (此处并没有创建一个结点) 
    //初始化一个空表
    InitList(L);
    //...后续代码... 
}

//判断单链表是否为空(不带头结点) 
bool Empty(LinkList L){
    if(L==NULL)
        return true;
    else
        return false;
} 

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

2.单链表的插入和删除操作

#include<iostream>
using namespace std;
//单链表按位序插入和删除操作
 

typedef struct LNode{  //定义单链表结点类型 
    ElemType data;  //数据域,每个结点存放一个数据元素 
    struct LNode *next;  //指针域,指针指向下一个结点 
}LNode, *LinkList; 

//在第i个位置插入元素e(带头结点) 
bool ListInsert(LinkList &L, int i, ElemType e){
    if(i<1)
        return false;

/*不带头结点
if(i==1){  //插入第1个结点的操作与其他节点操作不同 
    LNode *s=(LNode *)malloc(sizeof(LNode)); 
    s->date=e;
    s->next=L;
    L=s;
    return true;
}
    LNode *p;  //指针p指向当前扫描到的结点 
    int j=1;  //当前p指向的是第几个结点
*/
    LNode *p;  //指针p指向当前扫描到的结点 
    int j=0;  //当前p指向的是第几个结点 
    p=L;  //L指向头结点,头结点是第0个结点(不存数据) 
    while (p!=NULL&&j=i-1){  //循环找到第i-1个结点 
        p=p->next;
        j++;
    }
//  return InSertNextNode(p,e) //后插法在第i个位置上插入元素e 
    if(p==NULL)  //i值不合法 
        return false;
    LNode *s=(LNode *)malloc(sizeof(LNode));
    s->data=e;
    s->next=p->next;
    p->next=s;  //将结点s成功连到p之后 
    return true;   //插入成功 
}

//后插操作:在p结点之后插入元素e
bool InertNextNode(LNode *p, ElemType e){
    if(p==NULL)
        return false;
    LNode *s=(LNode*)malloc(sizeof(LNode));
    s->data=e;
    s->next=p->next;
    p->next=s;
    return true;
} 
//前插操作:在p节点之前插入元素e, (可以传入一个头指针LinkList L,先找到p的前驱结点,但时间复杂度O(n)
//前插操作:建立一个新的结点s作为p指针的后继结点,将p结点中的数据复制到s结点中,再用e覆盖p节点中的数据 
 bool InertPriorNode( LNode *p, ElemType e){
    if(p==NULL)
        return false;
    LNode *s=(LNode*)malloc(sizeof(LNode));
    if(s==NULL)  //内存分配失败 
        return false;
    s->next=p->next;  
    p->next=s;   //新结点s连到p之后 
    s->data=p->date;  //将p中的元素复制到s中 
    p->data=e;   //用e覆盖p中的元素 
    return true;
    
//王道书版本前插操作 直接给出了s结点前插到p结点 
bool InertPriorNode( LNode *p, LNode s){
    if(p==NULL|| s==NULL)
        return false;
    s->next=p->next;  
    p->next=s;   //新结点s连到p之后 
    ElemType temp=p->data; //交换p和s的数据域 
    p->data=s->data; 
    s->data=temp;
    return true;
}

//删除结点 (含头指针) 
bool ListDelete(LinkList &L,int i,ElemType &e) {
    if(i<1)
        return false;
    LNode *p;  //指针p指向当前扫描到的结点 
    int j=0;  //当前p指向的是第几个结点 
    p=L;  //L指向头结点,头结点是第0个结点(不存数据) 
    while (p!=NULL&&j=i-1){  //循环找到第i-1个结点 
        p=p->next;
        j++;
    }
    if(p==NULL)  //i值不合法 
        return false;
    if(p->next==NULL)
        returm false;
    LNode *q=p->next;  //令q指向被删除的结点
    e=q->date;  //用e返回元素的值 
    p->next=q->next;  //将*q结点从链中断开 
    free(q);  //释放结点的存储空间 
    return true;  //删除成功     
}

//删除指定结点p
bool DeleteNode(LNode *p){
    if(p==NULL)
        return false;
    LNode *q=p->next;  //令q指向*p的后继节点 
    p->data=p->next->data;  //和后继节点交换数据域 
    p->next=q->next;   //将*q节点从链中断开 
    free(q);  //释放后继结点的存储空间 
    reture true;
} 

3.单链表的按位序查找和按值查找

#include<iostream>
using namespace std;
//单链表按位序查找,按值查找
 

typedef struct LNode{  //定义单链表结点类型 
    ElemType data;  //数据域,每个结点存放一个数据元素 
    struct LNode *next;  //指针域,指针指向下一个结点 
}LNode, *LinkList; 

//按位查找,返回第i个元素(带头结点) 
LNode *GetElem(LinkList L,int i) {
    if(i<1)
        return NULL;
    LNode *p;  //指针p指向当前扫描到的结点 
    int j=0;  //当前p指向的是第几个结点 
    p=L;  //L指向头结点,头结点是第0个结点(不存数据) 
    while (p!=NULL&&j=i){  //循环找到第i个结点 
        p=p->next;
        j++;
    }
    return p;
}
//可以封装成函数,然后直接在插入和删除里面使用
//LNode *p=GetElem(L,i-1); 
 
/*王道书版本按位查找
LNode *GetElem(LinkList L, int i){
    int j=1;
    LNode *p=L->next;
    if(i==0)
        return L;
    if(i<1)
        return NULL;
    while(p!=NULL&&j<i){
        p=p->next;
        j++;
    }
    return p;
}*/
 
 
 LNode *LocateElem(LinkList L,ElemType e){
     LNode *p=L->next;//从第一个节点开始查找数据域为e的结点
     while (p!=NULL&&p->data!=e) 
         p=p->next;
     return p;  //找到后返回该结点指针,否则返回NULL; 
 }

4.单链表的建立

#include<iostream>
using namespace std;

//尾插法,头插法建立单链表
typedef struct LNode{  //定义单链表结点类型 
    ElemType data;  //数据域,每个结点存放一个数据元素 
    struct LNode *next;  //指针域,指针指向下一个结点 
}LNode, *LinkList; 

//初始化一个单链表(带头结点) 
bool InitList(LinkList &L){
    L=(LNode *)malloc(sizeof(LNode));  //分配一个头结点
    if(L==NULL)  //内存不足,分配失败 
        return false;
    L->next=NULL;  //头结点之后暂时还没有结点 
    return true; 
} 

void test(){
    LinkList L; //声明一个指向单链表的指针
    //初始化一个空表
    IniyList(L);
    //...后续代码 
}

//后插操作:在p结点之后插入元素e
bool InsertNextNode(LNode *p, ElemType e){
    if(p==NULL)
        return false;
    LNode *s=(LNode*)malloc(sizeof(LNode));
    if (s==NULL)  //内存分配失败 
        return false; 
    s->data=e;  //用结点s保存数据元素e 
    s->next=p->next;
    p->next=s;  //将结点s连到p之后 
    return true; 
    
//尾插法建立单链表
LinkList List_TailInsert(LinkList &L){  //正向建立单链表 
    int x;  //设ElemType为int整型 
    L=(LinkList)malloc(sizefo(LNode));  //建立头结点 ,初始化空表 
    LNode *s,*r=L;  //r为表尾指针 
    scanf("%d",&x);  //输入结点的值 
    while(x!=9999){  //设置一个特殊的数作为循环结束的条件 
        s=(LNode*)malloc(sizeof(LNode));  //在r结点之后插入x元素 
        s->data=x;  
        r->next=s;  //r指向新的表尾结点 
        r=s;
        scanf("%d",&x);
    }
    r->next=NULL;  //尾结点指针置空 
    return L;
} 

//头插法建立单链表
 LinkList List_HeadInsert(LinkList &L){  //逆向建立单链表 
    LNode *s; 
    int x;  
    L=(LinkList)malloc(sizeof(LNode));  //创建头结点 
    L->next=NULL;  //初始化空链表 
    scanf("%d",&x);  //输入结点的值 
    while(x!=9999){  //设置一个特殊的数作为循环结束的条件 
        s=(LNode*)malloc(sizeof(LNode));  //在创建新结点
        s->data=x;  
        s->next=L->next; 
        L->next=s;  //将新结点插入表中,L为头指针 
        scanf("%d",&x);
    } 
    return L;
}

三、双链表

#include<iostream>
using namespace std;
 //双链表 
 

typedef struct DNode{  //定义双链表结点类型 ,D是double 
     ElemType data;  //数据域 
     struct DNode *prior, *next;  //前驱和后继指针 
 }DNode, *DLinkList;
 
 //初始化双链表
 bool InitDLinkList(DLinkList &L){
     L=(DNode*)malloc(sizeof(DNode));  //分配一个结点 
     if(L==NULL)
         return false;
     L->prior=NULL;  //头结点的prior永远指向NULL 
     L->next=NULL;  //头结点之后暂时还没有结点 
     return true;
 } 
 
 void testDLinkList(){
     //初始化双链表 
     DLinkList L;
     InitDLinkList(L);
     //后续代码。。。 
 }
 
 //判断双链表是否为空(要带头结点)
 bool Emppty(DLinkList L){
     if(L->next==NULL)
         return true;
     else
         return false;
 } 
 
 //在p结点之后插入s结点
 /* bool InsertNextDNode(DNode *p, DNode *s){
      s->next=p->next;  //将结点*s插到结点p之后 
      p->next->prior=s;
      s->prior=p;
      p->next=s;
  } */
  //严谨处理之后 
  bool InsertNextDNode(DNode *p, DNode *s){
      if(p==NULL||s==NULL)  //非法参数
        return false; 
      s->next=p->next;  //将结点*s插到结点p之后 
      if(p->next!=NULL)  //如果p结点有后继节点 
          p->next->prior=s;
      s->prior=p;
      p->next=s;
      return true; 
  }
  
  //双链表的删除 删除p的后继结点q
   /*p->next=q->next;
   q->next->prior=p;
   free(q);*/
   //删除p的后继结点
   bool DeleteDNodeLinkList(DNode *p,){
       if(p==NULL)
           return false;
       DNode *q=p->next;  //找到p结点的后继结点q 
       if(q==NULL)  //p没有后继 
           return false;
       p->next=q->next;
       if(q->next!=NULL)  //q结点不是最后一个结点 
           q->next->prior=q;   
    free(q);  //释放结点空间 
    return true; 
}
                 
//销毁双链表 
void DestroyList(DLinkList &L){
    //循环释放各个数据结点
    while(L->next!=NULL)
        DeleteNextDNode(L);
    free(L);  //释放头结点 
    L=NULL;   //头指针指向NULL 
} 

//双链表的遍历(后向遍历) 
while(p!=NULL){
    //对结点p做相应处理,如打印
    p=p->next; 
} 
//双链表的遍历(前向遍历) 
while(p!=NULL){
    //对结点p做相应处理,如打印
    p=p->prior; 
} 
//双链表的遍历(前向遍历)跳过头结点 
while(p->prior!=NULL){
    //对结点p做相应处理,如打印
    p=p->prior; 
} 
//双链表不可以随机存取,按位查找(i++),按值查找(对比)操作都只能用遍历的方式 实现 

四、循环链表

//循环链表:循环单链表和循环双链表 
 

typedef struct LNode{  //定义单链表结点类型 
    ElemType data;  //数据域,每个结点存放一个数据元素 
    struct LNode *next;  //指针域,指针指向下一个结点 
}LNode, *LinkList; 

//初始化一个循环单链表
bool InitList(LinkList &L){
    L=(LNode *)malloc(sizeof(LNode));  //分配一个头结点
    if(L==NULL)  //内存不足,分配失败 
        return false;
    L->next=L;  //头结点next指向头结点 
    return true; 
} 

//判断单链表是否为空 
bool Empty(LinkList L){
    if(L->next==L)
        return true;
    else
        return false;
} 
//判断结点p是否为循环单链表的表尾结点 
bool isTail(LinkList L, LNode *p){
    if(p->next==L)
        return true;
    else
        return false;
}

 //循环双链表 
 typedef struct DNode{  //定义双链表结点类型 ,D是double 
     ElemType data;  //数据域 
     struct DNode *prior, *next;  //前驱和后继指针 
 }DNode, *DLinkList;
 
 //初始化循环双链表
 bool InitDLinkList(DLinkList &L){
     L=(DNode*)malloc(sizeof(DNode));  //分配一个结点 
     if(L==NULL)
         return false;
     L->prior=L;  //头结点的prior指向头结点 
     L->next=L;  //头结点的next指向头结点 
     return true;
 } 
 
void testDLinkList(){
     //初始化双链表 
     DLinkList L;
     InitDLinkList(L);
     //后续代码。。。 
 }
 
  //判断双链表是否为空(要带头结点)
 bool Emppty(DLinkList L){
     if(L->next==L)
         return true;
     else
         return false;
 }
 
//判断结点p是否为循环双链表的表尾结点 
bool isTail(DLinkList L, DNode *p){
    if(p->next==L)
        return true;
    else
        return false;
} 

//在p结点之后插入s结点 
bool InsertNextDNode(DNode *p, DNode *s){
      s->next=p->next;  //将结点*s插到结点p之后 
      p->next->prior=s;
      s->prior=p;
      p->next=s;
  } 
  
//删除p的后继结点q
p->next=q->next;
   q->next->prior=p;
   free(q); 

五、静态链表

//静态链表 ,不怎么考代码 

#include<iostream>
using namespace std;
#define MazSize 10  //静态链表的最大长度 
struct Node{  //静态链表结构类型的定义 
    ElemType data;  //存储数据元素 
    int next;  //下一个元素的数组下标 
}; 

void testSLinkList(){
    struct Node a[MaxSize]  //数组a作为一个静态链表 
    //后续代码。。。 
}

//课本上
#define MaxSize 10  //静态链表的最大长度 
typedef struct{  //静态链表结构类型的定义 
    ELemType data;  //存放数据元素 
    int next;  //下一个元素的数组下标 
}SLinkList[MazSize]; 
//后续用SLinkList定义变量a就是一个具有MazSize元素的数组
//并且每一个数组元素都是一个定义的结构体类型

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值