【冷门算法】不增加额外空间,将不带头结点链表递增排序

前言

第一次看到这题时两眼一黑,因为做惯了排序和链表大多都是带头链表且没有限制额外空间,这题叠了两个buff,很担心出题老头的精神状态。

一番搜索,都没有找到一个最优解,但是溯源到了一个母题,来自北大2015年。

算法代码

//不带头,题源北大2015
//直接插入排序
//list是不带头结点的线性链表,链表结点构造为data和link两个域,data是数据域,link是指针域。
//本算法将该链表按结点数据域的值的大小,从小到大重新链接。
LinkedList LinkListSort(LinkedList &list){
	p=list->link;                 //p是工作指针,指向待排序的当前元素。
	list->link=null;              //将原来的链表当做待插入的有序链表的头指针
	while(p!=null){
		r=p->link;    //r是p的后继。
		q=list;
		if(q->data > p->data) {   //处理待排序结点p比第一个元素结点小的情况。//更换头指针
			p->link=list;
			list=p; //链表指针指向最小元素,做有序链表的头指针
		}
		else{    //找最小值
			while(q->link!=null&&q->link->data < p->data) q=q->link;
                                //q指针遍历链表,寻找有序链表尾指针p真正对应的元素
			p->link=q->link;         //将当前排序结点链入有序链表中。
			q->link=p;
		}
		p=r;               //p指向下个待排序结点。
	}
}

算法思想与过程模拟

算法的运行主要考虑到:

①第一个数不是最小的;

②第二个数大于第一个数或小于第一个数;

③后一个数大于前一个数;

④后一个数小于前一个数;

⑤排序过程中不能断,所以需要一个r。

举例:有一个链表 2(L)→1→3→5→4

定义了一个p(工作指针),一个r(防止断链,始终在p之后),一个q(用于链接新的表)

代码行【6】p指向L的next,即1

【7】L(2)摘出来,单独成链

【8、9】进入p的大循环,r指向p后续(3)

【10】q指向L(2)

【11】第一次小循环,q(2)大于p,即第一个点大于待处理点p

【12】p(1)伪头插到L(2),此时新链为:  1(p)→2(L)

【13】L移到p(1),即保证L始终指向最小值(成为头),此时:1(p,L)→2

【21】p回到r,下一个是3

【9】r指向5

【10】q指向L(1)

【11】1p小于3q,跳到【15】

【16】判断q(1)next不为空且next小于p(3),的确,2小于3,q指向2

【18】p(3)指向q(2)的next(此时为NULL)

【19】q(2)链接p(3),此时:1(L)→2(q)→3(p)

【21、8、9、10】r指向4,p指向5,q指向1

【11】1小于5,5大于3,一样的,插到3之后

【21、8、9、10】r指向NULL,p指向4,q指向1

【11】1小于4,4大于5

【16】q遍历到3时,3的next(5)大于p,跳出while

【18】这一行的作用来了,p(4)next到q的next(5)

【19】q连接p,此时:1(L)→2→3(q)→4(p)→5

【21】【8】完成,跳出

附上一个带头结点的,按照顺序输出:

void fun(LinkList &head){
    while(head->next){            //循环到仅剩头结点 
        *pre=head;         //pre 为元素最小值结点的前驱结点的指针 
        *p=pre->next;      //p 为工作指针 
        while(p->next){ 
            if(p->next->data < pre->next-data) 
                pre=p;        //记住当前最小值结点的前驱 
        p=p->next; 
        }
        print(pre->next->data);         //输出元素最小值结点的数据 
        u=pre->next;           //删除元素值最小的结点,释放结点空间 
        pre->next=u->next; 
        free(u); 
    }  
    free(head);  
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

极限的哥哥

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值