2. 链表

使用以下作为链表的存储结构。带有头结点,其数值为-1。

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

考虑以下题目

1. 反向输出链表

    使用递归。第一次三分时写完,五分时完成调试;第二次六分钟共用完成调试。

void printReverseLinkList_2(LinkList h)
{
	if(h == NULL)
	{
		printf("\n");
		return;
	}
	printReverseLinkList_2(h->next);
	if(h->data != -1)
	    printf("%d, ", h->data);
}

2. 用O(1)的空间复杂度反转链表

    一开始以为不断将最后一个元素头插,就可以实现反转,但并不是这样。如果是O(n),使用头插入将很简单,但是O(1)实现这点要求我们更新插入位置。第一次6分时写完,13分时调试完毕;第二次6分时写完,18分钟时调试完毕。

void reverseLinkList_2(LinkList h, int len)
{
	if(len == 0 || len == 1) return;

    LNode* pretail = h;
    LNode* tail = pretail->next;
    LNode* insertPos = h;

    while(insertPos->next != NULL)
    {
    	pretail = h;
    	tail = pretail->next;
    	while(tail->next != NULL)
        {
        	pretail = pretail->next;
            tail = tail->next;
        }
        pretail->next = NULL;
        tail->next = insertPos->next;
        insertPos->next = tail;

    	insertPos = insertPos->next;
    }
}

3. 在链表中实现冒泡排序

    这个题目可以很好地考察我们对链表的基本操作,查询,插入等。第一次和第二次完成同时间,10分时写完,11分时调试完毕。

void sortLinkList_2(LinkList h, int len)
{
	LNode* pre = h;
	LNode* cmp1 = pre->next;
	LNode* cmp2 = pre->next->next;

	int i = 0, j = 0;
	for(i = len - 1; i >= 0; i--)
	{
		pre = h;
		cmp1 = pre->next;
		cmp2 = pre->next->next;
        for(j = 0; j < i; j++)
        {
        	if(cmp1->data > cmp2->data)
        	{
        		cmp1->next = cmp2->next;
        		cmp2->next = cmp1;
        		pre->next = cmp2;
        	}
        	pre = pre->next;
        	cmp1 = pre->next;
        	cmp2 = pre->next->next;
        }
	}
}

4. 设置一个递归算法,删除不带头结点的单链表L中所有值为x的结点

    6分钟写完,14分钟调试完毕,感觉较慢

void deleteXRecursively(LinkList l, int x)
{
    if(l->next == NULL) return;
    else if(l->next->data == x)
    {
        l->next = l->next->next;
        deleteXRecursively(l, x);
    }
    else
        deleteXRecursively(l->next, x);
}

5. 给定两个链表,找出两个链表的公共结点

    本题想到了暴力的方法,使用两个指针组合地遍历两个链表,复杂度为O(len1 * len2)。8分钟写完并调试完毕,感觉较慢。

    在思考过程中我注意到了如果两个链表有公共结点,那么应该是“Y”的形状,但是没有想清楚怎么利用这个点。一开始我所想的是从两个链表的结尾开始遍历,但是如何从单链表结尾开始遍历就是一个难题。答案中想到了先求出两个链表长度之差s,然后长的链表领先s个单位进行比较,是一个巧妙的方法。

    答案中的方法写出来8分钟。

LNode* findPublicLNode(LinkList m, LinkList n)
{
	LNode* i;
	LNode* j; //i for m, j for n
	for(i = m; i != NULL; i = i->next)
		for(j = n; j != NULL; j = j->next)
            if(i == j)
            	return i;
    return NULL;
}

int getLenLinklist(LinkList h)
{
	int len = 0;
	LNode* k = h->next;
	while(k != NULL)
	{
		len++;
		k = k->next;
	}
	return len;
}

LNode* findPublicLNode_2(LinkList m, LinkList n)
{
	int lm = getLenLinklist(m);
	int ln = getLenLinklist(n);

	LNode* i = m; 
	LNode* j = n;

	int d = lm - ln;
	int k = 0;
	if(d > 0)
        for(k = 0; k < d; k++) i = i->next;
    else
    	for(k = 0; k < d; k++) j = j->next;

    while(i != NULL)
    {
    	if(i == j) return i;
    	i = i->next;
    	j = j->next;
    }
    return NULL;
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值