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