数据结构___线性表的学习总结

概要

因为操作的需要现在重新学习了数据结构相关知识,故以此文来总结一下线性表的操作和基本知识 (很多函数linux内核已经设置了errno)

声明:因个人能力有限,本文仅是个人的学习记录笔记,有错误之处还望指出

线性表的基本概念和实现

1.线性表的定义

  • 线性表:具有相同特性的数据结构的元素组成的有限序列;
  • 线性表长度:序列中的元素个数,用(n >= 0)表示,n可以为0,表示为空表;

2.线性表的逻辑特性
线性表只有一个表头元素和表尾元素,表头元素没有前驱,表尾元素没有后继,其余元素都只有一个直接前驱和一个直接后继。

3.线性表的存储结构
线性表的存储结构有顺序存储链式存储两种,即顺序表和链表。

顺序表的特性:

  • 随机访问,时间复杂度为o(1);
  • 占用连续的存储空间 (存储分配只能预先进行,一旦分配好了,始终不变)
  • 插入操作的时候要移动多个元素

链表的特性:

  • 不支持随机访问,时间复杂度为o(n);
  • 支持存储空间的动态访问
  • 插入操作只需移动链表即可,无需移动元素

线性表的结构体定义和基本操作

1.顺序表的结构体定义

#define  MAXSIZE 100;           //定义顺序表的元素个数
typedef struct {
    int data[MAXSIZE];           //存放顺序表的数组
    int length;                 //定义顺序表长度(元素个数)
}Sqlist;

2.单链表的节点定义

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

3.双链表的节点定义

typedef struct DLNode{
    int data;                     //数据域
    struct DLNode *next;         //指向前驱结点的指针
    struct DLNode *prior;       //指向后继结点的指针
}DLNode;

重点:结点是内存中一片由用户分配的存储空间,只有一个地址来表示它的存在,没有显示的名称。所以在分配链表结点空间的时候,同时定义一个指针,用来存储这片空间的地址,并且用这个指针名称来作为结点名称。

4.顺序表的操作

  • 按值查找算法
int findElem(Sqlist L,int e){
    int i;
    for(i = 0; i < L.length;i++){
        if(L.data[i] == e)
            break;
        else 
            return -1;
    }    
    return i;
}
  • 插入元素的算法
//因为此次要插入数据,故采用引用型
/*
*@先找到要插入的位置,然后将插入位置以后的数据后移,放入数据,并将表长加一
*/
int insertElem(Sqlist &L,int p,int e){
    int i;
    //判断插入位置是否有效
    if(p<0||p>L.length||L.length == MAXSIZE)
    return 0;
    for(i=L.length-1;i>=p;--i)
        L.data[i+1]=L.data[i];
    e=L.data[p];
    ++(L.length);               //表长+1
    return 1;
}
  • 删除元素的算法
//因为此次要删除数据,故采用引用型
/*
*@先找到要删除的位置,然后将删除位置以后的数据前移,并将表长减一
*/
//for循环的限制条件length具体怎么求,要将末尾的结果待人最后一次计算,确定
int deleteElem(Sqlist &L,int p,int &e){
    int i;
    //判断插入位置是否有效
    if(p<0||p>L.length-1)
    return 0;
    e=L.data[p];
    for(i=p;i<=L.length-1;++i)
        L.data[1]=L.data[i+1];
    e=L.data[p];
    --(L.length);               //表长-1
    return 1;
}

5.单链表的操作

  • 两个递增的单链表归并成递增的单链表算法
//将元素值单调递增的链表A,B连接成有序递增的链表C
void merge(LNode *&C,LNode *A,LNode *B){
    LNode *p = A->next;             //指向第一个数据结点
    LNode *q = B->next;
    LNode *r;                      //r始终指向C的终端结点        
    C = A;                          //用A的头来做C的头                
    C->next = NULL;
    free(B);                        //B的头结点已经无用,释放内存
    r = C;                          //r指向c此时既是头结点也是终端结点
    while(p!=NULL && q!=NULL){      //当p,q都不为空的时候开始比较,小的放入c中
        if(p->data >= q->data){
            r->next = q;
            q = q -> next;                  //尾插法的思想
            r = r ->next; 
        }else{
            r->next = p;
            p = p -> next;      
            r = r -> next;
        }

    }
        r->next = NULL;
        //当还有结点未成功连接上时
        if(p != NULL)
        r->next = p;
         if(q != NULL)
        r->next = q;
}

  • 有n个元素已经存储在数组A中,用尾插法建立链表C
void createList(LNode *&C,int A[],int n){
    LNode *s,*r;        //新建两个结点,r始终指向终端结点,s用来指向新申请的结点
    int i;
    C=(LNode *)malloc(sizeof(LNode));
    C->next = NULL;
    r = C;                              //r指向头节点,此时的头结点就是终端结点
    for(i = 0 ; i < n ; ++i){
        s=(LNode *)malloc(sizeof(LNode));
        s->data=a[i];
        r->next = s;
        r= r->next;
    }
    r->next=NULL;
}
  • 将两个链表归并成递减的单链表
void merge(LNode *&C,LNode *A,LNode *B){
    LNode *p =A->next;
    LNode *q =B->next;
    LNode *r;
    C=A;
    C->next = NULL;
    r = C;
    free(B);
    while(p != NULL && q != NULL){
        if(p->data >= q-> data){            //头插法
            r = p;
            r->next = C->next;
            C->next = r;
        }else{
            r = q;
            r->next = C->next;
            C->next = r;
        }
    }
    //两个链表的元素个数不一样的时候,将其他元素加入链表
    while(p!=NULL){
        r=p;
        p=p->next;
        r->next = C->next;
    }
      while(q!=NULL){
        r=q;
        q=q->next;
        r->next = C->next;
    }

}
  • 查找链表(有头结点)中的值为X的结点并删除
int findAnddelete(LNode *C,int x){
    LNode *q,*p;
    p=c;
    while(p->next !=NULL ){
        if(p->next->data == x)
            break;
        p=p->next;
    }
    //查找部分结束
    if(p->next==NULL)
        return 0;
    else{
        q=p->next;
        p->next=p->next->next;
        free(q);
    }

    return 1;
}

6.双链表的操作

  • 采用尾插法建立双链表
void createDlistR(DLnode *L,int a[],int n){
    DLnode *s,*r;
    int i;
    L=(DLnode *)malloc(sizeof(DLnode));
    L->prior=NULL;
    L->next=NULL;
    r=L;            //和单链表一样,r始终指向终端结点(开头结点也是尾结点)
    for(i=0; i < n ; ++i){
        s=(DLnode *)malloc(sizeof(DLnode));             //创建新的结点
        s->data=a[i];                   //把s查到r的尾部,并r指向s
        r->next = s;
        s-prior = r;
        r=s;
    }
    r->next = NULL;             //链表结尾
}

  • 查找结点的算法
//在双链表中查找第一个值为x的结点,成功返回结点,失败返回NULL
DLnode *findNode(DLnode *c,int x){
    DLnode q=c;
    while(q->next != NULL){
        if(q->data == x)
            break;
        q=q->next;
    }
    return q;               //如果找到则返回结点q,没找到q的内容也为NULL,将返回值统一
}
  • 插入结点的算法
//在双链表中插入结点
//s为要插入的节点
s->next = p->next;
s->prior = p;
p->next = s;
s->next->prior = s;

  • 删除结点的算法
//在双链表中删除结点
//q为要删除的结点
q=p->next;
p->next=q->next;
q->next->prior = p;
free(q);        //释放内存
而塞过 2021-3-21

关于我:一个就要进入互联网,经历社会毒打的99小伙

下一站(javascript)
下一站(html)

你可能感兴趣的:(数据结构,链表,指针,数据结构,算法)