【数据结构 - 线性表】自学笔记记录(完结)

目录

一、顺序表

1、顺序表的存储结构

2、创建一个空顺序表

3、顺序表取值

4、顺序表查找对应的值

5、顺序表插入元素

6、顺序表删除元素

二、单链表

1、单链表的存储结构 

2、创建一个空单链表

3、单链表取值

4、 单链表查找对应的值

5、单链表的插入

6、单链表的删除

7、头插法创建单链表

8、尾插法创建单链表

9、单链表的整表删除

三、循环链表

1、将两带头结点的循环链表合并

2、将两带尾指针的循环链表合并

3、实例——约瑟夫环问题

四、双向链表

1、双向链表存储结构

2、双向链表的插入

3、双向链表的删除

五、顺序表与链表比较


一、顺序表

 用一组地址连续的存储单元依次存储线性表的数据元素的方式,具有顺序存储结构的特点。

线性表的顺序存储结构是一种随机存取的存储结构

                                     

 注意:顺序表的 a(i) 对应数组下标的 i-1,顺序表中位置要比数组中多1

1、顺序表的存储结构

#define MAXSIZE 100         //顺序表可能达到的最大长度
#define LISTINCREMENT 2     //线性表存储空间的分配增量

typedef struct 
{
   ElemType *elem;         //存储空间的基地址
   int length;             //当前长度
   int listsize;           //当前分配的存储容量
}SqList;            //顺序表的结构类型为SqList

2、创建一个空顺序表

Status InitList(SqList &L) 
{
      L.elem = (ElemType *)malloc(MAXSIZE*sizeof(ElemType));
      //L.elem = new ElemType[MAXSIZE];     
      if (!L.elem) exit(OVERFLOW);        //存储分配失败退出
      L.length = 0;                       //空表长度为0
      L.listsize = MAXSIZE;        //顺序表的当前存储量为最大
      return OK;
}

3、顺序表取值

用e返回第 i 个数据元素的值

Status GetElem(SqList L, int i, ElemType &e) 
{
    if(L.length==0 || i < 1 || i > L.length) return ERROR; 
    e = L.elem[i - 1];      //a(i)对应的数组是i-1
    return OK;
}

4、顺序表查找对应的值

在顺序表中找到值为e的数据元素,并返回其在顺序表中的位置

int FindELem(SqList L, ElemType e) 
{
        for (i = 0; i < L.length; i++)
            if(L.elem[i] == e)
                return i + 1;         //顺序表中的位置要比数组多1
          
        return 0;                               
}

5、顺序表插入元素

在第i个位置插入元素e

数组法

Status Insert(SqList &L, int i, ElemType e) 
{
        //因为可以插在最后,所以i值的合法范围是 1~L.length+1
        if ((i < 1) || (i > L.length + 1)) 
            return ERROR;                       
        
        if (L.length >= L.listsize) //存储空间已满
        {
            ElemType *newbase;
            newbase = (ElemType*)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType));
            if(!newbase) return;
            L.elem = newbase;
            L.listsize += LISTINCREMENT;
        }          

        for (j = L.length-1; j >= i-1; j--)   //j=L.length-1表示从顺序表最后一个元素开始
            L.elem[j + 1] = L.elem[j];          //插入位置及之后的元素后移
        
        L.elem[i - 1] = e;         
        L.length ++;                                      
        return OK;
}

指针法 

void InsertList_Sq(SqList &L, int i, ElemType e)
{
    if(i<1||i>L.length+1) return;

    if(L.length>=L.listsize)
    {
        ElemType *newbase;
        newbase = (ElemType*)realloc(L.elem,(L.listsize+LISTINCREMENT)*sizeof(ElemType));
        if(!newbase) return;
        L.elem = newbase;
        L.listsize += LISTINCREMENT;
    }
    ElemType *p = &(L.elem[i-1]); //指针p指向第i个元素
    ElemType *q = &(L.elem[L.length-1]); //指针q指向最后一个元素
    for(q ;q>=p;q--)
        *(q+1) = *q;

    *p = e;
    L.length++;
}

6、顺序表删除元素

删除第i个位置的元素,并把要删除的元素放在e中

数组法

Status Delete(SqList &L, int i , ElemType &e) 
{
        //i值的合法范围是 1~L.length
            if ((i < 1) || (i > L.length)) 
                return ERROR; 

            e = L.elem [i-1];
            for (int j = i; j <= L.length - 1; j++)   //因为删除了一个元素,所以表长-1
                L.elem[j - 1]=L.elem[j];             //被删除元素之后的元素前移
            
            L.length --;                                     
            return OK;
}

指针法 

void DeleteList_Sq(SqList &L, int i, ElemType &e)
{
    if(i<1||i>L.length) return;

    ElemType *p = &(L.elem[i-1]);
    e = *p;

    ElemType *q = L.elem+L.length-1;//把q指针定位到最后一个元素

    for(++p;p<=q;++p)
        *(p-1) = *p;

    L.length--;
}

总结:只有顺序表的取值是O(1),其他操作都是O(n)

二、单链表

  • 首元结点:链表中存储第一个数据元素的结点。
  • 头结点:是在首元素结点之前附设的一个结点,其指针指向首元结点。
  • 头指针:是指向链表中第一个结点的指针
  • 若链表设有头结点,则头指针所指结点为线性表的头结点。
  • 若链表不设头结点,则头指针所指结点为该线性表的首元结点。

 

  • 带头结点的单链表为空时:head->next == NULL
  • 不带头结点的单链表为空时:head == NULL

1、单链表的存储结构 

typedef struct LNode 
{
    ElemType data;          //数据域
    struct LNode *next;     //指针域
}LNode,*LinkList;         //LinkList为指向结构体LNode的指针类型

LNode规定为结点的类型,*LinkList规定为链表类型 

eg:LNode *p  //  LinkList p 

2、创建一个空单链表

void InitList( LinkList &L )
{
    L = (LinkList)malloc(sizeof(LNode));
    if(!L) return;
    L->next = NULL;
}

3、单链表取值

取第i个元素的值,用e返回L中第i个数据元素的值

Status GetElem(LinkList L, int i, ElemType &e) 
{
        LinkList p;
        int j = 1;

        p = L->next;   //p指向首元结点
                                    
        while (p && j < i)  //若j=i则跳出循环 此时p指到i位置
        {                
            p = p->next;         
            j++;                           
        }

        if (!p || j > i) return ERROR;   //若p指向空则返回错误     
        e = p->data;           
        return OK;
}

4、 单链表查找对应的值

在单链表中找到值为e的数据元素,并返回值为e的结点地址p

LNode *FindELem(LinkList L, Elemtype e) 
{
        p = L->next;
                            
        while (p && p->data != e)  
            p = p->next;                 
        
        return p;          //查找成功返回值为e的结点地址p, 查找失败p为NULL
}

5、单链表的插入

在第i个位置插入值为e的新结点

 Status Listinsert(LinkList &L, int i, ElemType e) 
{
        LinkList p,s;
        int j = 1;

        p = L;    //p先和头指针指向一个地方
        
        while (p && j < i) 
        {
            p = p->next;
            j++;                                //查找到第i-1个结点,p指向该结点
        }

        if (!p || j > i ) return ERROR; 

        s = (LNode*)malloc(sizeof(LNode));                          

        s->data = e;                  

        s->next = p->next;       

        p->next = s;  

        return OK;
    }

6、单链表的删除

删除第i个位置的结点

Status Delete(LinkList &L, int i) 
{

        LinkList p;
        int j = 1;

        p=L;

        while ((p->next) && (j < i)) //如果第i个结点不为空
        {              
            p = p->next;
            j++;                //p指向第i-1个结点
        }

        if (!(p->next) || (j > i))  return ERROR;    
       
        q = p->next;                                   
        p->next = q->next;                              
        free(q);                                       
        return OK;
}

7、头插法创建单链表

输入顺序和输出顺序相反

void HeadCreate( LinkList &L, int n)
{
        LinkList p;
        L=( LNode* )malloc(sizeof(LNode));
        L->next=NULL;

        for(int i=0;i < n;i++)
        {
            p=( LNode* )malloc(sizeof(LNode));
            scanf("%d",&p->data);
            p->next = L->next;
            L->next = p;
        }
}

8、尾插法创建单链表

输入顺序和输出顺序相同

void TailCreate( LinkList &L, int n)
{
        LinkList p,r;
        L=( LNode* )malloc(sizeof(LNode));
        L->next=NULL;
        r=L;

        for(int i=0;i < n;i++)
        {
            p=( LNode* )malloc(sizeof(LNode));
            scanf("%d",&p->data);
            r->next = p;
            r = p;
        }
        r->next = NULL;
}

9、单链表的整表删除

Status ClearList( LinkList &L )
{
    LinkList p,q;
    
    p=L->next;

    while(p)  //当p指向的结点不为空
    {
        q=p->next;
        free(p);
        p=q;
    }
    
    L->next = NULL;
}
   

三、循环链表

1、将两带头结点的循环链表合并

Status UnionList_H( LinkList LA, LinkList LB )
{
    LinkList p,q;

    p=LA;
    while( p->next != LA ) p=p->next; //把p指针移到LA表尾
    q=LB;
    while( q->next != LB ) q=q->next; //把q指针移到LB表尾

    p->next = LB->next;
    free(LB);
    q->next = LA;

    return LA;
}

2、将两带尾指针的循环链表合并

Status UnionList_T( LinkList RA, LinkList RB )
{
    LinkList p;

    p=RA->next; //p指针指向表A的头结点

    RA->next = RB->next->next; //RA连接表B的首元结点
    
    free(RB->next); //释放表B头结点

    RB->next = p;
    
    return RB;
}

3、实例——约瑟夫环问题

N个人围成一圈顺序编号,从1号开始按1、2、3......顺序报数,报p者退出圈外,其余的人再从1、2、3开始报数,报p的人再退出圈外,以此类推。 请按退出顺序输出每个退出人的原序号。

输入格式:

输入只有一行,包括一个整数N(1<=N<=3000)及一个整数p(1<=p<=5000)。

输出格式:

按退出顺序输出每个退出人的原序号,数据间以一个空格分隔,但行尾无空格。

输入样例:

在这里给出一组输入。例如:

7 3

输出样例:

3 6 2 7 5 1 4
#include <stdio.h>
#include <stdlib.h>

typedef struct Node
{
    int data;
    struct Node *next;
}Node;

Node *create(int n)
{
    Node *p,*L,*s;
    int i = 1;
    L=(Node*)malloc(sizeof(Node));
    p = L;
    
        while(i <= n)
        {
            s=(Node*)malloc(sizeof(Node));
            s->data=i++;
            p->next=s;
            p=s;
        }
        s->next = L->next;
    
    free(L);
    return s->next; //返回第一个结点的地址
}

int main()
{
    int m,n,i;
    scanf("%d %d",&n,&m); //n是总人数,数到m退出

    Node *p=create(n); //p指针指向循环链表的第一个结点,即编号1的人
    Node *temp;

    //m%=n;

    while(p != p->next)
    {
        for(i=1;i<m-1;i++) //把p指向要淘汰的前一个人头上
            p=p->next;
            
        printf("%d ",p->next->data);

        //删除死掉的人
        temp=p->next;
        p->next=temp->next;
        free(temp);

        p = p->next;
    }
    printf("%d",p->data);
}

四、双向链表

1、双向链表存储结构

typedef struct LNode
{
    ElemType data;
    struct LNode *piror,*next;
}LNode,* DoubleList;

2、双向链表的插入

在第i个位置前插入元素e

Status Insert( DoubleList &L,int i,ElemType e)
{
    DoubleList p,s;
    int j = 1;
    while(!p && j<=i) //让p指针指向第i个结点
    {
        p=p->next;
        j++;
    }
    s=(LNode*)malloc(sizeof(LNode));
    
    if(s)
    {
        s->data = e;
        s->prior = p->prior;        //1
        p->prior->next = s;         //2
        s->next = p;                //3
        p->prior = s;               //4
        return OK;           //1、2||3、4内部可换,但两组位置不可颠倒
     }
     return NO;
}

3、双向链表的删除

删除第i个元素,并把删除值存入e中

Status Delete( DoubleList &L,int i,ElemType &e)
{
    DoubleList p;
    
    int j = 1;

    while(!p && j<=i )
    { 
        p = p->next;
        j++;
    }
    
    e = p->data;
    
    p->prior->next = p->next;
    p->next->prior = p->prior;
    free(p);
}

五、顺序表与链表比较

  • 7
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值