数据结构练习题:用双向循环链表实现顺序递增存储若干自然数,比如输入一个整数10,则建立一个双向循环链表,里面的每个节点分别存放1,2,3,4,5,6,7,8,9,10,然后通过某些操作。。。

数据结构练习题:

用双向循环链表实现顺序递增存储若干自然数,比如输入一个整数10,则建立一个双向循环链表,里面的每个节点分别存放1,2,3,4,5,6,7,8,9,10,然后通过某些操作,将其重新排列成1,3,5,7,9,10,8,6,4,2,即奇数升序偶数降序,并在屏幕上打印出来。

相信你已经掌握了“双向循环链表”的相关结构知识,以及其“增删改查”的基本工作方式。接下来本人将会直接分析这道题目。

首先看题目的前半段:“用双向循环链表实现顺序递增存储若干自然数,比如输入一个整数10,则建立一个双向循环链表,里面的每个节点分别存放1,2,3,4,5,6,7,8,9,10。”

前半段题目要求对一个头节点,进行连续的“尾插”尾插,输入的内容是1到一个你自己设定的最大正整数。所有用for()循环函数连续“尾插”即可。

//下面的代码只是完整代码的摘要,文章最后面会给出完整代码
/**
  ***********************************
  *@brief  尾插_自动生成从1到最大值的链表
  *@param  p : 头节点
  *@param  max : 生成数字最大值
  *@retval None
  ***********************************
  */
void link_add_tail_auto(plink_t p,int max)
{
	int data;
	for (data = 1; data <= max; data++)
	{
		link_add_tail(p,data);
	}
}

/**
  ***********************************
  *@brief  尾插
  *@param  p : 头节点
  *@param  d : 数据
  *@retval None
  ***********************************
  */
void link_add_tail(plink_t p,datatype d)
{
	//创建新的节点
	plink_t node = NULL;
	link_init(&node);
	if(node==NULL)
		return;
	node->data = d;

	//将新的节点插在头的前面
	insert_forward(p,node);
}

/**
  ***********************************
  *@brief  一个节点node插在p的前面
  *@param  p  node : 节点
  *@retval None
  ***********************************
  */
static void insert_forward(plink_t p,plink_t node)
{
	node->next = p;
	node->prev = p->prev;
	p->prev->next = node;
	p->prev = node;
}

typedef int datatype;
typedef struct link{
	datatype data;
	struct link *prev;
	struct link *next;
} link_t,*plink_t;

再来看题目的后半段:“每个节点分别存放1,2,3,4,5,6,7,8,9,10,然后通过某些操作,将其重新排列成1,3,5,7,9,10,8,6,4,2,即奇数升序偶数降序,并在屏幕上打印出来。”

进行“奇数升序,偶数降序”操作的最简单办法是:用一个指针从头节点逆向读取链表数据,将读取到的偶数节点进行“尾插”操作。即插入到头节点的前面。

“读取用的指针”从链表的尾部开始移动,“剪切用的指针”不断指向“读取用的指针”。

 “读取用的指针”往前移动一位。

 “剪切用的指针”的数据是偶数就进行尾插,插入头节点的前面。是奇数就直接跳过,不操作。

“读取用的指针”指到头节点就停下来。

 

 

 

 

//下面的代码只是完整代码的摘要,文章最后面会给出完整代码
/**
  ***********************************
  *@brief  排序_奇数升序,偶数降序
  *@param  p : 头节点
  *@retval None
  ***********************************
  */
void sort_rise_down(plink_t p)
{
	plink_t head_p = p;
  plink_t read_p = p->prev;
	plink_t cut_p = NULL;

	while (read_p!=head_p)
	{
    cut_p = read_p;
    read_p = read_p->prev;
		if(0 == (cut_p->data % 2))/* 判断是否为偶数 */
		{
			cut_to_tail(head_p,cut_p);
		}
		display(head_p);
	}
}

/**
  ***********************************
  *@brief  剪贴节点_尾插
  *@param  p : 头节点
  *@param  node : 需要剪贴并尾插的节点
  *@retval None
  ***********************************
  */
void cut_to_tail(plink_t p,plink_t node)
{
	cut_node(node);
	insert_forward(p,node);
}

/**
  ***********************************
  *@brief  剪切
  *@param  node : 节点
  *@retval None
  ***********************************
  */
static void cut_node(plink_t node)
{
	node->prev->next = node->next;
	node->next->prev = node->prev;
}

/**
  ***********************************
  *@brief  一个节点node插在p的前面
  *@param  p  node : 节点
  *@retval None
  ***********************************
  */
static void insert_forward(plink_t p,plink_t node)
{
	node->next = p;
	node->prev = p->prev;
	p->prev->next = node;
	p->prev = node;
}

运行一下程序看看效果。

 下面放出所有代码。

复制完成之后更改相对应的文件名,然后编译代码。

我这边的运行环境是Ubuntu18,使用编译命令“gcc link.c main.c -o app -Wall -O0 -g”。

头文件代码

//文件名:link.h

#ifndef __LINK_H
#define __LINK_H

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

typedef int datatype;

typedef struct link{
	datatype data;
	struct link *prev;
	struct link *next;
} link_t,*plink_t;

extern void link_init(plink_t *p);
extern void link_add_head(plink_t p,datatype d);
extern void link_add_tail(plink_t p,datatype d);
extern void link_del(plink_t p,datatype d);
extern void link_update(plink_t p,datatype old,datatype new);
extern void display(plink_t p);
extern void pre_display(plink_t p);
extern void link_add_tail_node(plink_t p,plink_t node);
extern void link_add_tail_rise(plink_t p,datatype d);
extern void link_add_tail_auto(plink_t p,int max);
extern void sort_rise_down(plink_t p);
extern void sort_rise_down_2(plink_t p);
extern void cut_to_tail(plink_t p,plink_t node);
extern void cut_to_head(plink_t p,plink_t node);

#endif

自定义函数代码文件

//文件名:link.c

/* 双向循环链表*/
#include "link.h"

/**
  ***********************************
  *@brief  一个节点node插在p的后面
  *@param  p  node : 节点
  *@retval None
  ***********************************
  */
static void insert_behind(plink_t p,plink_t node)
{
	node->next = p->next;
	node->prev = p;
	p->next->prev = node;
	p->next = node;
}

/**
  ***********************************
  *@brief  一个节点node插在p的前面
  *@param  p  node : 节点
  *@retval None
  ***********************************
  */
static void insert_forward(plink_t p,plink_t node)
{
	node->next = p;
	node->prev = p->prev;
	p->prev->next = node;
	p->prev = node;
}

/**
  ***********************************
  *@brief  剪切
  *@param  node : 节点
  *@retval None
  ***********************************
  */
static void cut_node(plink_t node)
{
	node->prev->next = node->next;
	node->next->prev = node->prev;
}

/**
  ***********************************
  *@brief  新旧节点的替换
  *@param  old 旧节点
  *@param  new 新节点
  *@retval None
  ***********************************
  */
static void replace(plink_t old,plink_t new)
{
	new->next = old->next;
	new->prev = old->prev;
	new->next->prev = new;
	new->prev->next = new;
}



/**
  ***********************************
  *@brief  初始化 (创建头节点)
  *@param  p : 头节点
  *@retval None
  ***********************************
  */
void link_init(plink_t *p)
{
	*p=(plink_t)malloc(sizeof(link_t));
	if(*p==NULL){
		perror("malloc error");
		return;
	}
	
	(*p)->prev = (*p);
	(*p)->next = (*p);
}  

/**
  ***********************************
  *@brief  头插
  *@param  p : 头节点
  *@param  d : 数据
  *@retval None
  ***********************************
  */
void link_add_head(plink_t p,datatype d)
{
	//创建新的节点
	plink_t node = NULL;
	link_init(&node);
	if(node==NULL)
		return;
	node->data = d;
	
	//将新的节点插在头的后面
	insert_behind(p,node);
}

/**
  ***********************************
  *@brief  尾插
  *@param  p : 头节点
  *@param  d : 数据
  *@retval None
  ***********************************
  */
void link_add_tail(plink_t p,datatype d)
{
	//创建新的节点
	plink_t node = NULL;
	link_init(&node);
	if(node==NULL)
		return;
	node->data = d;

	//将新的节点插在头的前面
	insert_forward(p,node);
}


/**
  ***********************************
  *@brief  删除
  *@param  p : 头节点
  *@param  d : 需要删除的数据
  *@retval None
  ***********************************
  */
void link_del(plink_t p,datatype d)
{
	plink_t head = p;
	
	plink_t node = NULL;
	
	//找到该节点
	while(p->next!=head){
		node = p->next;
		if(node->data == d){
			
			//剪切并删除该节点
			cut_node(node);
			node->prev = node;
			node->next = node;
			free(node);
			continue;
		}
		p = p->next;
	}
}


/**
  ***********************************
  *@brief  更新
  *@param  p : 头节点
  *@param  old : 旧节点
  *@param  new : 新节点
  *@retval None
  ***********************************
  */
void link_update(plink_t p,datatype old,datatype new)
{
	plink_t head = p;
	plink_t node = NULL;
	plink_t new_node = NULL;
	
	//遍历寻找old
	while(p->next!=head){
		node = p->next;
		if(node->data == old){
			
			//找到后,创建新的节点new
			link_init(&new_node);
			if(new_node==NULL)
				return;
			new_node->data = new;
			
			//新的节点替换old
			replace(node,new_node);
			
			//释放old
			node->prev = node;
			node->next = node;
			free(node);
		}
		
		p = p->next;
	}
}


/**
  ***********************************
  *@brief  正序遍历
  *@param  p : 头节点
  *@retval None
  ***********************************
  */
void display(plink_t p)
{
	plink_t head = p;
	
	printf("正序遍历结果为:");
	while(p->next!=head){
		p = p->next;
		printf("%d ",p->data);
	}
	printf("\n");
	
}


/**
  ***********************************
  *@brief  逆序遍历
  *@param  p : 头节点
  *@retval None
  ***********************************
  */
void pre_display(plink_t p)
{
	plink_t head = p;
	
	printf("逆序遍历结果为:");
	while(p->prev!=head){
		p = p->prev;
		printf("%d ",p->data);
	}
	printf("\n");
	
}

/**
  ***********************************
  *@brief  尾插_节点
  *@param  p : 头节点
  *@param  node : 要插入的节点
  *@retval None
  ***********************************
  */
void link_add_tail_node(plink_t p,plink_t node)
{
	//将新的节点插在头的前面
	insert_forward(p,node);
}

/**
  ***********************************
  *@brief  尾插_自动排序递增
  *@param  p : 头节点
  *@param  d : 生成数字的最大值
  *@retval None
  ***********************************
  */
void link_add_tail_rise(plink_t p,datatype d)
{
	int flag = 0;
	//创建新的节点
	plink_t node = NULL;
	link_init(&node);
	if(node==NULL)
		return;
	node->data = d;

	plink_t head_p = p;
	while(p->next!=head_p)
	{
		p = p->next;
		printf("d:%d ",d);
		printf("p->data:%d \n",p->data);
		if(d < p->data)
		{
			printf("break\n");
			//将新的节点插在p节点的前面
			insert_forward(p,node);
			printf("前插:%d\n",d);
			flag = 1;
			break;
		}
	}

	if (p->next == head_p && flag == 0)
	{
		//将新的节点插在p节点的后面
		insert_behind(p,node);
		printf("后插:%d\n",d);
	}
}

/**
  ***********************************
  *@brief  尾插_自动生成从1到最大值的链表
  *@param  p : 头节点
  *@param  max : 生成数字最大值
  *@retval None
  ***********************************
  */
void link_add_tail_auto(plink_t p,int max)
{
	int data;
	for (data = 1; data <= max; data++)
	{
		link_add_tail(p,data);
	}
}

/**
  ***********************************
  *@brief  剪贴节点_尾插
  *@param  p : 头节点
  *@param  node : 需要剪贴并尾插的节点
  *@retval None
  ***********************************
  */
void cut_to_tail(plink_t p,plink_t node)
{
	cut_node(node);
	insert_forward(p,node);
}

/**
  ***********************************
  *@brief  剪贴节点_头插
  *@param  p : 头节点
  *@param  node : 需要剪贴并头插的节点
  *@retval None
  ***********************************
  */
void cut_to_head(plink_t p,plink_t node)
{
	cut_node(node);
	insert_behind(p,node);
}

/**
  ***********************************
  *@brief  排序_奇数升序,偶数降序
  *@param  p : 头节点
  *@retval None
  ***********************************
  */
void sort_rise_down(plink_t p)
{
	plink_t head_p = p;
  	plink_t read_p = p->prev;
	plink_t cut_p = NULL;

	while (read_p!=head_p)
	{
    cut_p = read_p;
    read_p = read_p->prev;
		if(0 == (cut_p->data % 2))/* 判断是否为偶数 */
		{
			cut_to_tail(head_p,cut_p);
		}
		display(head_p);
	}
}

/**
  ***********************************
  *@brief  排序2_奇数升序,偶数降序
  *@param  p : 头节点
  *@retval None
  ***********************************
  */
void sort_rise_down_2(plink_t p)
{
	plink_t head_p = p;
	plink_t read_p = p;
	plink_t cut_p = p;
	plink_t flag_p = p;
	while (read_p->next!=flag_p)
	{
		read_p = read_p->next;
		if(0 == (read_p->data % 2))/* 判断是否为偶数 */
		{
			cut_p = read_p;
			read_p = read_p->prev;
			cut_to_tail(flag_p,cut_p);
			flag_p = cut_p;
		}
		display(head_p);
	}
}

运行文件

//文件名:main.c

#include "link.h"

int main(void)
{
	plink_t head_p = NULL;
	link_init(&head_p);
	if(head_p==NULL)
		return -1;
	printf("head_p:%p\n",head_p);
	
	int max;
	printf("请输入一个正整数:");
	scanf("%d",&max);
	printf("开始自动尾插\n");
	link_add_tail_auto(head_p,max);
	display(head_p);
	printf("执行“奇数升序,偶数降序”操作\n");
	sort_rise_down(head_p);
	display(head_p);
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值