LinearList

1、线性表的定义

    线性表是具有相同特性数据元素的一个有限序列。该序列中所含元素的个数叫做线性表的长度,用n(n>0)表示。n可以为0,表示该线性表是一个空表。

2、线性表的逻辑特性

    只有一个表头元素,只有一个表尾元素,表头元素没有前驱,表尾元素没有后继,除表头和表位元素之外,其他元素只有一个直接前驱,也只有一个直接后继。

3、结构体定义

#define maxSize 100 //这里定义一个整型常量maxSize,值为100

//1、顺序表的结构体定义
typedef struct{
    int data[maxSize];  //存放顺序元素的数组(默认是int型,可根据题目要求将int转换成其他的数据类型)
    int length; //存放顺序表的长度
}Sqlist;    //顺序表类型的定义

//2、单链表结点定义
typedef struct LNode{
    int data;   //data中存放结点数据域(默认是int型)
    struct LNode *next; //指向后继结点的指针
}LNode; //定义单链表结点类型

//3、双链表结点定义
typedef struct DLNode{
    int data;   //data中存放结点数据域(默认是int型)
    struct DLNode *prior;   //指向前驱结点的指针
    struct DLNode *next;    //指向后继结点的指针
}DLNode;    //定义双链表结点类型

4、顺序表的操作

//返回第一个比x大的元素的位置
int findElem(Sqlist L, int x)
{
    int i;
    for (i=0; i<L.length; ++i)
    {
        if (x < L.data[i])  //对顺序表中的元素从小到大逐个进行判断,看x是否小于当前所扫描到的元素,如果小于则返回当前位置i
        {
            return i;
        }
    }
    return i;   //如果顺序表中不存在比x大的元素,则应将x插入表尾元素,返回i来标记这种情况(i<L.length这一句不成立,而退出for循环后,i正好指示了表尾元素之后的位置,同样也是正确的插入位置)
}

//移动元素、并插入新的元素
void insertElem(Sqlist &L, int x)   //L本身要发生变化,因此要使用引用型
{
    int p,i;
    p = findElem(L,x);  //调用函数findElem()来找到插入位置p
    for (i=L.length-1; i>=p; --i)
    {
        L.data[i+1] = L.data[i];    //从右向左,逐个将元素右移一个位置
    }
    L.data[p] = x;  //将x放在插入位置p上
    ++(L.length);   //表内元素多了1个,因此表长自增1
}

//在顺序表中查找第一个值为e的元素算法
int findElem(Sqlist L, int e)
{
    int i;
    for (i=0; i<L.length; ++i)
    {
        if (e == L.data[i])
        {
            return i;   //若找到,则返回下标
        }
    }
    return -1;  //没找到,返回-1,作为失败标记
}

//在第P个位置插入元素e
int insertElem(Sqlist &L, int p, int e) //L本身要发生改变,所以要有引用型
{
    int i;
    if (p<0 || p>L.length || L.length==maxSize) //位置错误或者表长已经达到顺序表的最大允许值,此时插入不成功,返回0
    {
        return 0;
    }
    for (i=L.length-1; i>=p; --i)
    {
        L.data[i+1] = L.data[i];    //从后往前,逐个将元素往后移动一个位置
    }
    L.data[p] = e;  //将e放在插入位置P上
    ++(L.length);   //表内元素多了1个,长度自增1
    return 1;   //插入成功,返回1
}

//删除顺序表L中下标为p(0<=p<=length-1)的元素,成功返回1,否则返回0,并将被删除元素的值赋给e。
int deleteElem(Sqlist &L, int p, int &e)
{
    int i;
    if (p<0 || p>L.length-1)
    {
        return 0;   //位置不对返回0,代表删除不成功
    }
    e = L.data[p];  //将被删除元素的值赋给e
    for (i=p; i<L.length-1; ++i)    //从p位置开始,将其后边的元素逐个前移一个位置
    {
        L.data[i] = L.data[i+1];
    }
    --(L.length);   //表长减1
    return 1;   //删除成功,返回1
}

//初始化顺序表的算法
//只需将length设置为0,如下:
void initList(Sqlist &L)    //L本身要发生改变,所以用引用型
{
    L.length = 0;
}

//求指定位置元素的算法
//用e返回L中p(0<=p<=length-1)位置上的元素,如下:
int getElem(Sqlist L, int p, int &e)    //要改变,所以用引用型
{
    if (p<0 || p>L.length-1)    //p值越界错误,返回0
    {
        return 0;
    }
    e = L.data[p];
    return 1;
}

5、单链表的操作

//将两个递增的单链表归并成一个递增的单链表
void merge(LNode *A, LNode *B, LNode *&C)
{
    LNode *p = A->next; //p来跟踪A的最小值结点
    LNode *q = B->next; //q来跟踪B的最小值结点
    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都不为空时,选取p与q所指结点中较小者插入C的尾部
    {
        /**
        以下的if else语句中,r始终指向当前链表的终端结点,作为接纳新结点的一个媒介,通过它,新结点被链接入C并且重新指向新的终端结点,以便于接收下一个新结点,这里体现了建立链表的尾插法的思想
        */
        if (p->data <= q->data)
        {
            r-next = p;
            p = p->next;
            r = r->next;
        }
        else
        {
            r->next = q;
            q = q->next;
            r = r->next;
        }
    }
    r->next = NULL; //此句可去掉
    if (p != NULL)  //将p及p之后链接到C的尾部
    {
        r->next = p;
    }
    if (q != NULL)  //将q及q之后链接到C的尾部
    {
        r->next = q;
    }
}

//尾插法建立单链表
void createlistR(LNode *&C, int a[], int n) //要改变的变量用引用型
{
    LNode *s,*r;    //s用来指向新申请的结点,r始终指向C的终端结点
    int i;
    C = (LNode*)malloc(sizeof(LNode));  //申请C的头结点空间
    C->next = NULL;
    r = C;  //r指向头结点,因为此时头结点就是终端结点
    for (i=0; i<n; ++i) //循环申请n个结点来接收数组a中的元素
    {
        s = (LNode*)malloc(sizeof(LNode));  //s指向新申请的结点
        s->data = a[i]; //用新申请的结点来接收a中的一个元素
        r->next = s;    //用r来接收新结点
        r = r->next;    //r指向终端结点,以便于接纳下一个到来的结点
    }
    r->next = NULL; //数组a中所有的元素都已经装入链表C中,C的终端结点的指针域置为NULL,C建立完成
}

//头插法建立单链表
void createlistF(LNode *&C, int a[], int n)
{
    LNode *s;
    int i;
    C = (LNode*)malloc(sizeof(LNode));
    C->next = NULL;
    for (i=0; i<n; ++i)
    {
        s = (LNode*)malloc(sizeof(LNode));
        s->data = a[i];
        //头插法的关键
        s->next = C->next;  //s所指新结点的指针域next指向C中的开始结点
        C->next = s;    //头结点的指针域next指向s结点,使得s成为新的开始结点
    }
}

//利用头插法将两个递增的单链表归并成一个递减的单链表
void merge(LNode *A, LNode *B, LNode *&C)
{
    LNode *p = A->next;
    LNode *q = B->next;
    LNode *s;
    C = A;
    C->next = NULL;
    free(B);
    while (p != NULL && q != NULL)
    {
        if (p->data <= q->data)
        {
            s = p;
            p = p->next;
            s->next = C->next;
            C->next = s;
        }
        else
        {
            s = q;
            q = q->next;
            s->next = C->next;
            C->next = s;
        }
    }
    /**
    下边这两个循环是和求递增归并序列不同的地方,必须将剩余元素逐个插入C的头部才能得到最终的递减序列
    */
    while (p != NULL)
    {
        s = p;
        p = p->next;
        s->next = C->next;
        C->next = s;
    }
    while (q != NULL)
    {
        s = q;
        q = q->next;
        s->next = C->next;
        C->next = s;
    }
}

//查找链表C(带头结点)中是否存在一个值为x的结点,若存在,则删除该结点并返回1,否则返回0
int findAndDelete(LNode *C, int x)
{
    LNode *p, *q;
    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];
        /**
        下边3句将s插入到L的尾部,并且r指向s,s->prior = r;这一句是和建立单链表不同的地方
        */
        r->next = s;
        s->prior = r;
        r = s;
    }
    r->next = NULL;
}

//在双链表中查找元素x,并返回结点指针
DLNode* findNode(DLNode *C, int x)
{
    DLNode *p = C->next;
    while (p != NULL)
    {
        if (p->data == x)
        {
            break;
        }
        p = p->next;
    }
    return p;   //如果找到,则p中内容是结点地址(循环因break结束);如果没找到,则p中内容是NULL(循环因p等于NULL而结束)。
}

//插入结点的算法
//假设在双链表中p所指的结点之后插入一个结点s,其操作语句如下:
s->next = p->next;
s->next = p;
p->next = s;
s->next->prior = s; //假如p指向最后一个结点,则本行可去掉

//删除结点的算法
//设要删除双链表中p结点的后继结点,其操作语句如下:
q = p->next;
p->next = q->next;
q->next->prior = p;
free(q);


  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值