C语言程序设计(王立柱)第八章答案 链表

先附一个

node.h

list.h

Josephus.c

#pragma once
//node.h
#include<stdlib.h>

typedef struct Node{
	Type data;
	struct Node* prev;
	struct Node* next;
}Node;

Node* GetNode(Type item, Node* p, Node* n);
Type GetData(Node* itr) { return itr->data; }
Node* GetPrev(Node* itr) { return itr->prev; }
Node* GetNext(Node* itr) { return itr->next; }

Node* GetNode(Type item, Node* p, Node* n) {
	Node* re;
	re = (Node*)malloc(sizeof(Node));
	re->data = item;
	re->prev = p;
	re->next = n;
	return re;
}




#pragma once
//list.h
#include"node.h"

typedef struct {
	Node* head;
	Node* tail;
	int size;
}List;

void InitList(List* l);							//准构造函数,建立空表
int Size(List* l) { return l->size; }
int Empty(List* l) { return l->size == 0; }

//读取区间边界
Node* Begin(List* l) { return l->head->next; }	//读取数据首节点指针
Node* End(List* l) { return l->tail; }			//读取链表尾节点指针

Node* Insert(List* l, Node* itr, Type item);	//定点插入到itr前面
void PushFront(List* l, Type item) { Insert(l, Begin(l), item); }//首插
void PushBack(List* l, Type item) { Insert(l, End(l), item); }//尾插

Node* Erase(List* l, Node* itr);				//删除itr指向的结点,返回后继指针
void PopFront(List* l) { Erase(l, Begin(l)); }	//首删
void PuopBack(List* l) { Erase(l, GetPrev(End(l))); }//尾删

void Clear(List* l) { while (!Empty(l))PopFront(l); }//清表
void FreeList(List* l) { Clear(l); free(l->head); free(l->tail); }//准析构函数

void InitList(List* l) {
	l->head = GetNode(0, NULL, NULL);
	l->tail = GetNode(0, 0, 0);
	l->head->next = l->tail;
	l->tail->prev = l->head;
	l->size = 0;
}
Node* Insert(List* l, Node* itr, Type item) {
	//Node* p = itr;
	itr->prev->next = GetNode(item, itr->prev, itr);
	itr->prev = itr->prev->next;
	l->size++;
	return itr->prev;
}
Node* Erase(List* l, Node* itr) {
	//Node* p = itr;
	Node* re = itr->next;
	itr->prev->next = itr->next;
	itr->next->prev = itr->prev;
	free(itr);
	l->size--;
	return re;
}




//Josephus.c
#include<stdio.h>
#include<time.h>
typedef int Type;
#include"list.h"

void OutputList(List* l);
void Josephus(int n);

int main() {
	int n;
	printf("Enter the number of people:\n");
	scanf("%d", &n);
	Josephus(n);
	return 0;
}
void OutputList(List* l) {
	Node* first = Begin(l);
	Node* last = End(l);
	for (; first != last; first = GetNext(first))
		printf("%d\t", GetData(first));
	printf("\n");
}
void Josephus(int n) {
	int counter;					//计数器
	int step;						//随机步长
	Node* first;
	Node* last;
	List Party;						//参与者
	List Loser;						//淘汰者
	List Odd;						//随机步长
	InitList(&Party);
	InitList(&Loser);
	InitList(&Odd);

	for (counter = 1; counter <= n; counter++)
		PushBack(&Party, counter);	//参赛者输入
	printf("Party:\n");				//参赛者输出
	OutputList(&Party);

	srand(time(0));
	first = Begin(&Party);			//数据首结点
	last = End(&Party);				//链表尾结点
	while (Size(&Party) > 1) 
	{
		step = 1 + rand() % 10;
		PushBack(&Odd, step);
		for (counter = 1; counter < step; counter++) {
			first = GetNext(first);			//计算步数一步步把first移到淘汰者处
			if (first == last)				//把链表尾结点转到数据首结点
				first = Begin(&Party);
		}
		PushBack(&Loser,GetData(first));				//淘汰者入Loser
		first = Erase(&Party, first);		//淘汰者淘汰
		if (first == last)				//把链表尾结点转到数据首结点
			first = Begin(&Party);
	}
	printf("Odds:\n");
	OutputList(&Odd);
	printf("Loser:\n");
	OutputList(&Loser);
	printf("Winner:\n");
	printf("%d\n", *Begin(&Party));
//用 printf 语句来打印结构体类型的变量,结果是 undefined behavior!
//什么是未定义行为,就是说发生任何状况都是可能的,这个就要看编译器的实现方式了。
//当然改成GetData(Begin(&Party))就没问题了。

	FreeList(&Party);
	FreeList(&Loser);
	FreeList(&Odd);
}

有两个点需要注意

第一:书上的代码printf("%d\n", *Begin(&Party));这是不严谨的,应该改GetData(Begin(&Party)),虽然结果是对的,但是由于编译器的行为不同,可能出现不同的结果。我找到这个问题的答案来源于blog.csdn.net/weixin_42181686/article/details/117102972?ops_request_misc=&request_id=&biz_id=102&utm_term=%E5%A6%82%E6%9E%9Cprintf%E7%9A%84%25d%E5%8D%B4%E6%98%AF%E4%B8%80%E4%B8%AA%E7%BB%93%E6%9E%84%E6%80%8E%E4%B9%88%E5%8A%9E&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-.pc_search_download_positive&spm=1018.2226.3001.4187

第二,书上的list的插入和删除函数都新定义了一个Node* p; 来p=itr; 我觉得去掉也没区别,因此这导致了我一上午的折磨,调用GetNext()和Erase()函数时无数次first变成空指针然后访问越界程序异常终止,我人都快折磨疯了又换回书上的代码然后运行成功了,这没什么,关键是我百思不得其解又找不到答案就又改回了自己的代码,然后又每次都成功了,wtm,无话可说

题目:

选择排序和链表复制(只贴源文件,需要的头文件前面已经贴了)

#include<stdio.h>
typedef int Type;
#include"list.h"

void OutputList(const List* l);
void Selection(List* l);
void Copy(const List* lo, List* lt);
Node* MaxOfNode(Node* n);

int main() {
	int n;
	int i;
	List lo;
	List lt;
	InitList(&lo);
	InitList(&lt);
	int temp = 0;
	printf("输入链表长度n和n个整数:\n");
	scanf("%d", &n);
	for (i = 0; i < n; i++) {
		scanf("%d", &temp);
		PushBack(&lo, temp);
	}
	Selection(&lo);
	Copy(&lo, &lt);
	OutputList(&lo);
	OutputList(&lt);
	FreeList(&lo);
	FreeList(&lt);
	return 0;
}
void OutputList(const List* l) {
	Node* first = Begin(l);
	Node* last = End(l);
	for (; first != last; first = GetNext(first))
		printf("%d\t", GetData(first));
	printf("\n");
}
Node* MaxOfNode(Node* n) {
	int i;
	Node* temp = n;
	Node* max = temp;
	while (temp->next->next != 0) {//temp最多为倒数第二个数据结点
		if (GetData(max) < GetData(temp->next))
			max = temp->next;
		temp = temp->next;
	}
	return max;
}
void Selection(List* l) {
	Node* max;
	Node* temp = Begin(l);//temp是从第一个到倒数第二个数据节点的定位标
	while (temp->next->next != 0) {//temp最多为倒数第二个数据结点
		max = MaxOfNode(temp);
		if (max == temp) {
			temp = temp->next;
			PushFront(l, GetData(temp->prev));
			Erase(l, temp->prev);
		}
		else {
			PushFront(l, GetData(max));
			Erase(l, max);
		}
	}
	PushFront(l, GetData(End(l)->prev));
	Erase(l, End(l)->prev);
}
void Copy(const List* lo, List* lt) {
	Node* one = Begin(lo);
	while (one->next != 0) {
		PushBack(lt, GetData(one));
		one = one->next;
	}
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值