C语言(十一)

1、在单链表实现约瑟夫环

输入:输入多个整型数创造链表L(-1表示输入结束)、出圈时的报数k。

输出:输出链表L剩下的最后一个结点值。

优化目标:无。
思路:找到尾结点,让尾结点的next指针指向头结点,形成一个环。然后进入循环,每经过k次,删除一个结点。

#include <stdio.h>
#include <stdlib.h>

struct ListNode {
    int data;
    struct ListNode *next;
};

void JosephCycle(struct ListNode *L,int k)
{
	struct ListNode *str, *tail,*p;
	int i=0;
	str=L;
	tail=L;
	while (tail->next)//找到尾结点
	{
		tail=tail->next;
	} 
	tail->next=L;//形成环
	while (str->next!=str)//只有一个元素时退出循环
	{
		i++;	
		if(i==k){
		//报到k的结点被删除(交换前后结点值,删除后结点)
		printf("删除%d\n",str->data);
		p=str->next;
		str->data=p->data;
		str->next=p->next;
		i=0;//重新报数
		free(p);
		}
		str=str->next;
	} 
	printf("最后剩下%d\n",str->data);
}

struct ListNode* readlist()//创建链表
{
    struct ListNode *head=NULL,*tail=NULL,*p=NULL;
    int data;
    printf("输入链表元素: ");
    scanf("%d", &data);
    while (data!=-1)
    {
        p=(struct ListNode*)malloc(sizeof(struct ListNode));
        p->data=data;
        p->next=NULL;
        if (head==NULL)
            head=p;
        else
            tail->next=p;
        tail=p; printf("输入链表元素: ");
        scanf("%d", &data);
    }
    return head;
}

void printlist(struct ListNode *L )//打印链表
{
     struct ListNode *p=L;
     while (p) {
           printf("%d ", p->data);
           p=p->next;
     }
     printf("\n");
}

int main()
{
    int k; printf("输入k: ");
    scanf("%d",&k);
    struct ListNode *L=readlist();
    JosephCycle(L,k);
    return 0;
}

2、单链表冒泡排序

输入:输入多个整型数创造链表L(-1表示输入结束)。

输出:输出链表L冒泡排序后的序列。

优化目标:设置flag,当某一轮没有发生交换时,排序提前结束。
思路:设置三个指针count、cur和tail,count用于控制外循环的次数,cur和tail用于控制内循环。tail开始为NULL,cur和count均指向头结点。每一轮比较cur->data与cur->next->data的大小,若前者大于后者则交换,否则不交换。每一轮交换完成后,tail指针都前移一位,并将cur重新指向头结点,再开始新一轮的交换,直至外循环中count->next==NULL结束整个循环。

#include <stdio.h>
#include <stdlib.h>

struct ListNode {
    int data;
    struct ListNode *next;
};

void Swap(int *a, int *b)
{
	int tmp=*a;
    *a=*b;
    *b=tmp;
  }
  
void BubbleSort(struct ListNode *L)
{
	int flag;
	struct ListNode *count=L;
    struct ListNode *tail=NULL;
    for(;count!=NULL;count=count->next){//外循环,一共循环链表的长次
    	struct ListNode *cur=L;//每次从链表头开始往后交换
    	flag=0;
        for(;cur->next!=tail;cur=cur->next){//内循环,cur最终位置在尾结点之前
            if(cur->data>cur->next-> data){
            	flag=1;
            	Swap(&cur->data, &cur->next->data);
            }
        }
    	tail=cur;//更新tail,tail往前一步
    	if (flag==0)//本轮没发生交换,则排序完成
        {
            return;
        }
    }

}

struct ListNode* readlist()//创建链表
{
    struct ListNode *head=NULL,*tail=NULL,*p=NULL;
    int data;
    scanf("%d", &data);
    while (data!=-1)
    {
        p=(struct ListNode*)malloc(sizeof(struct ListNode));
        p->data=data;
        p->next=NULL;
        if (head==NULL)
            head=p;
        else
            tail->next=p;
        tail=p;
        scanf("%d", &data);
    }
    return head;
}

void printlist(struct ListNode *L )//打印链表
{
     struct ListNode *p=L;
     while (p) {
           printf("%d ", p->data);
           p=p->next;
     }
     printf("\n");
}

int main()
{
    int m;
    struct ListNode *L=readlist();
    printlist(L);
    BubbleSort(L);
    printlist(L);
    return 0;
}

ps:将冒泡排序与链表两者结合考察,是一个重点。

3、查找单链表的中间结点

输入:输入多个整型数创造链表L(-1表示输入结束)。

输出:输出链表L的中间结点。

优化目标:无。
思路:本题需要采用快慢指针。之前做查找链表中倒数第k个结点的题,也运用了快慢指针。定义两个指针fast和slow,开始它们都指向头结点,slow每走一步,fast就走两步。当fast走到最后的时候,slow所指的节点就是中间节点。

#include <stdio.h>
#include <stdlib.h>

struct ListNode {
    int data;
    struct ListNode *next;
};
  
struct ListNode* FindMidNode(struct ListNode head){
    struct ListNode *slow=head;
    struct ListNode *fast=head;
    while(fast!=NULL&&fast->next!=NULL){//直到fast为最末元素跳出循环
        fast=fast->next->next;//走两步                                                                                                                                                         
        slow= slow->next;//走一步
    }
    printf("%d ", slow->data);
    return slow; 
}

struct ListNode* readlist()//创建链表
{
    struct ListNode *head=NULL,*tail=NULL,*p=NULL;
    int data;
    scanf("%d", &data);
    while (data!=-1)
    {
        p=(struct ListNode*)malloc(sizeof(struct ListNode));
        p->data=data;
        p->next=NULL;
        if (head==NULL)
            head=p;
        else
            tail->next=p;
        tail=p;
        scanf("%d", &data);
    }
    return head;
}

void printlist(struct ListNode *L )//打印链表
{
     struct ListNode *p=L;
     while (p) {
           printf("%d ", p->data);
           p=p->next;
     }
     printf("\n");
}

int main()
{
    int m;
    struct ListNode *L=readlist();
    printlist(L);
    struct ListNode *mid=FindMidNode(L);
    return 0;
}

总结:今天练习了几道链表的经典例题,加深了对知识的理解和运用,在练习的同时也回顾了链表。除去上面的题之外,之前写过的求两个有序链表的交集、并集以及链表的逆置都很重要。经过这一段时间的学习后,回过头来做这些题思路都要开阔很多,但还是需要不断地复习巩固,不能做了就丢。明天计划复习一下字符串的内容,这一部分还有点欠缺。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值