线性链表的一些基本算法

/*1、假设有两个按元素值递增次序排列的线性表,均以单链表形式存储。请编写算
法将这两个单链表归并为一个按元素值递减次序排列的单链表,并要求利用原来
两个单链表的结点存放归并后的单链表。*/

List *List_merge(List *La, List *Lb)
{
    List *p, *q, *r;
    p = La->next;    //使用p指针指向la的下一个元素
    La->next = NULL; //把LA的下一个元素置为空指针
    q = Lb->next;    //q指针指向lb的下一个元素
    while (p != NULL && q != NULL)
    {
        if (p->data < q->data) //头插法,结果与插入顺序相反
        {
            r = p->next; //使用r指针保存p指向的下一个元素指针
            p->next = La->next;
            La->next = p;
            p = r;
        }
        else
        {
            r = q->next;
            q->next = La->next;
            La->next = q;
            q = r;
        }
    }
    while (p != NULL)
    {
        r = p->next;
        p->next = La->next;
        La->next = p;
        p = r;
    }
    while (q != NULL)
    {
        r = q->next;
        q->next = La->next;
        La->next = q;
        q = r;
    }
    return La;
}

/*2.带头结点且头指针为ha和hb的两线性表A和B 分别表示两个集合。
两表中的元素皆为递增有序。请写一算法求A和B的并集AUB。要求
该并集中的元素仍保持递增有序。且要利用A和B的原有结点空间。*/

List *merge_List(List *head1, List *head2)
{
    List *La, *Lb, *r, *tail;
    La = head1->next;
    Lb = head2->next;
    head1->next = NULL;
    tail = head1;

    while (La != NULL && Lb != NULL)
    {
        if (La->data < Lb->data)
        {
            r = La->next;
            tail->next = La;
            tail = tail->next;
            La = r;
        }
        else if (La->data > Lb->data)
        {
            r = Lb->next;
            tail->next = Lb;
            tail = tail->next;
            Lb = r;
        }
        else if (La->data = Lb->data) //要考虑到两个节点相等的情况,当相等时,不插入,工作指针移动到下个节点
        {
            r = La->next;
            La = r;
        }
    }
    while (La != NULL)
    {
        r = La->next;
        tail->next = La;
        tail = tail->next;
        La = r;
    }
    while (Lb != NULL)
    {
        r = Lb->next;
        tail->next = Lb;
        tail = tail->next;
        Lb = r;
    }
    return head1;
}

/*3、知L1、L2分别为两循环单链表的头结点指针,m,n分别为L1、L2
表中数据结点个数。要求设计一算法,用最快速度将两表合并成一个带
头结点的循环单链表。
思路:移动L1链表的指针到链表尾,然后将其指向L2的首元节点,而后
移动L2链表的指针到链表尾,将其指导L1的头指针即可*/

List *merge_List(List *head1, List *head2)
{
    List *La, *Lb;
    La = head1->next;
    Lb = head2->next;
    while (La->next != head1)
    {
        La = La->next;
    }
    La->next = Lb;
    while (La->next != head2)
    {
        Lb = Lb->next;
    }
    Lb->next = head1;
    return head1;
}

/*设计一个递归算法,删除不带头结点的单链表L中所有值为x的结点*/
//算法一(不带头结点)
void Del_X_3(Linklist &L, ElemType x)
{
    LNode *p;      //p指向待删除结点
    if (L == NULL) //递归出口
    {
        return;
    }
    if (L->data == x)
    {          //若L所指结点的值为x
        p = L; //删除*L,并让L指向下一结点
        L = L->next;
        free(p);
        Del_X_3(L, x); //递归调用
    }
    else                     //若L所指结点的值不为x
        Del_X_3(L->next, x); //递归调用
}
//算法二(带头结点)
void del(LinkList &L,ElemType x){
    LNode *p,*q;
    p = L->next;
    if(p==null){
        return;
    }
    if(p->data==x){
        q=p;
        p=p->next;
        free(q);
        del(p,x);
    }else{
        del(p->next,x);
    }
}

//算法三(非递归算法)
void del(LinkList &L,ElemType x){
    LNode *p,*q;
    p=L->next;
    while(p!=null){
        if(p->data==x){
            q=p;//用q指针指向p指针
            p=p->next;//p指针指向后继节点
            free(q);//删除q节点
        }else{
            p=p->next;
        }
    }
}


/*试编写在带头结点的单链表L中删除一个最小值结点的高效算法(假设最小值结点时唯一的)*/
/*算法思想:用p从头至尾扫描单链表,pre指向*p结点的前驱,用minp保存值最小的结点指针(初值为p),
minpre指向*minp结点的前驱(初值为pre)。一边扫描,一边比较,若p->data小于minp->dara,则将p、
pre分别复制给minp、minpre。
当p扫描完毕,minp指向最小值结点,minpre指向最小值结点的前驱结点,再将minp所指结点删除即可。*/

LinkList Delete_Min(LinkList &L)
{
    //L是带头结点的单链表,本算法删除其最小值结点
    LNode *pre = L, *p = pre->next; //p为工作指针,pre指向其前驱
    LNode *minpre = pre, *minp = p; //保存最小值结点及其前驱
    while (p != NULL)
    {
        if (p->data < minp->data)
        {
            minp = p; //找到比之前找到的最小值结点更小的结点
            minpre = pre;
        }
        pre = p; //继续扫描下一个结点
        p = p->next;
    }
    minpre->next = minp->next; //删除最小值结点
    free(minp);
    return L;
}

/*试编写算法将带头结点的单链表就地逆置,所谓“就地”是指辅助空间复杂度为O(1)。*/

LinkList Reverse_1(LinkList L)
{
    //L是带头结点的单链表,本算法将L就地逆置
    LNode *p, *r;   //p为工作指针,r为p的后继,以防断链
    p - L->next;    //从第一个元素结点开始
    L->next = NULL; //先将头结点L的next域置为NULL
    while (p != NULL)
    {                      //依次将元素结点摘下
        r = p->next;       //暂存p的后继
        p->next = L->next; //将p结点插入到头结点之后
        L->next = p;       //
        p = r;             //
    }
    return L;
}

/*有一个带头结点的单链表L,设计一个算法使其元素递增有序。
算法思想:采用直接插入排序算法的思想,先构成只含一个数据结点
的有序单链表,然后依次扫描单链表中剩下的结点*p(直至p==NULL为止),
在有序表中通过比较查找插入*p的前驱结点*pre,然后*p插入到*pre之后,
找到合适的位置插入
*/

void Sort(LinkList &L)
{
    //本算法实现将单链表L的结点重拍,使其递增有序
    LNode *p = L->next, *pre;
    LNode *r = p->next; //r保持*p后继结点指针,以保证不锻炼
    p->next = NULL;     //构造只含一个数据结点的有序表
    p=r;
    while (p != NULL)
    {
        r = p->next; //保存*p的后继结点指针
        pre = L;
        while (pre->next != NULL && pre->next->data < p->data)
        {
            pre = pre->next; //在有序表中查找插入*p的前驱结点*pre
        }
        p->next = pre->next; //将*p插入到*pre后
        pre->next = p;
        p = r; //扫描原单链表中剩下的结点
    }
}

/*设在一个带头结点的单链表中所有元素结点的数据值无序,试编写一个函数,
删除表中所有介于给定的两个值(作为函数参数给出)之间的元素的元素(若存在)

因为链表是无序的,所以只能逐个节点进行检查,执行删除。

*/

void RangeDelete(LinkList &L, int min, int max)
{
    LNode *pr = L, *p = L->link,*q; //p是检测指针,pr是其前驱
    while (p != NULL)
    {
        if (p->data > min && p->data < max)
        { //寻找到被删结点,删除
            q=p;
            pr->link = p->link;
            free(q);
            p = pr->link;
        }
        else
        { //否则继续寻找被删结点
            pr = p;
            p = p->link;
        }
    }
}

/*设A={a1,b1,a2,b2…,an,bn}线性表,采用带头结点的la单链表存放,设计一个就地算法,将其拆分为两个线性表,使得
A={a1,a2,…,an} B={bn,…,b2,b1}

二者的差别仅在于对B表的建立不采用尾插法,而是采用头插法。
*/

LinkList DisCreat(LinkList &A)
{
    LinkList B = (LinkList)malloc(sizeof(LNode)); //创建B表表头
    B->next = NULL;                               //B表的初始化
    LNode *p = A->next, *q;                       //p为工作指针
    A->next=NULL;
    LNode *ra = A; //ra始终指向A的尾结点
    while (p != NULL)
    {
        ra->next = p;
        ra = p; //将*p链到A的表尾
        p = p->next;
        q = p->next;       //头插后,*p将断链,因此用q记忆*p的后继
        p->next = B->next; //将*p插入到B的前端
        B->next = p;
        p = q;
    }
    ra->next = NULL; //A尾结点的next域置空
    return B;
}
/*在一个递增有序的线性表中,有数值相同的元素存在。若存储方式为单链表,
设计算法去掉数值相同的元素,使表中不再有重复的元素。例如(7,10,10,21,30,42,42,42,51,70)将变作(7,10,21,30,42,51,70)
算法思想:由于是有序表,所有相同值域的结点都是相邻的。用p扫描递增单链表L,若*p结点的值域等于其后继结点的值域,则删除后者,否则p移向下一个结点
*/
void Del_Same(LinkList &L)
{
    //L是递增有序的单链表,本算法删除表中数值相同的元素
    LNode *p = L->next, *q; //p为扫描工作指针
    if (p == NULL)
        return;
    while (p->next != NULL)
    {
        q = p->next; //q指向*p的后继节点
        if (p->data == q->data)
        {                      //找到重复值的结点
            p->next = q->next; //释放*q结点
            free(q);           //释放相同元素值的结点
        }
        else
            p = p->next;
    }
}

/*设A和B是两个单链表(带头结点),其中元素递增有序,设计一个算法从A和B中公共元素产生单链表C,要求不破坏A B 的结点
算法思想:表A ,B都有序,可从第一个元素起一次比较A、B量表的元素,若元素值不等,则值小的指针往后移,若元素值相等,
则创建一个值等于两结点的元素值的新的结点,使用尾插法插入到新的链表中,并两个原表指针后移一位,直到其中一个链表遍历到表尾。

*/

void Get_Common(LinkList A, LinkList B)
{
    //本算法产生单链表A和B的公共元素的单链表的C
    LNode *p = A->next, *q - B->next, *r, *s;
    LinkList C = (LinkList)malloc(sizeof(LNode)); //建立表C
    r = C;                                        //r始终指向C的尾结点
    while (p != NULL && q != NULL)
    { //循环挑出条件
        if (p->data < q->data)
            p = p->next; //若A的当前元素较小,后移指针
        else if (p->data > q->data)
            q = q->next; //若B的当前元素较小,后移指针
        else
        { //找到公共元素结点
            s = (LNode *)malloc(sizeof(LNode));
            s->data = p->data; //复制产生结点*s
            r->next = s;       //将*s链接到C上(尾插法)
            r = s;
            p = p->next; //表A和表B继续向后扫描
            q = q->next;
        }
    }
    r->next = NULL; //置C尾结点指针为空
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值