数据结构习题解析与实验指导第八章(排序)课后算法设计题

1.试以单链表为例,实现简单的选择排序算法。

#include <iostream>
using namespace std;

struct Node {
	int data;
	Node* next;
	Node(int data = 0, Node* next = 0):
		data(data),
		next(next)
	{
		
	}

};

/*题目要求的选择排序*/
void sort(Node& list) {
	Node* tail = &list;
	while (tail->next != 0)
	{
		Node* head = tail;
		Node* minHead = tail;
		while (head->next != 0)  //从head开始寻找【最小结点】的【上一结点】
		{
			if (head->next->data < minHead->next->data) {
				minHead = head;
			}
			head = head->next;
		}
		//将【最小结点】摘除,然后插入tail之后
		Node* temp = minHead->next;
		minHead->next = minHead->next->next;
		temp->next = tail->next;
		tail->next = temp;
		
		//tail指针向后移动
		tail = temp;
	}
}

void display(Node& list) {
	Node* node = list.next;
	while (node != 0)
	{
		cout << node->data << " ";
		node = node->next;
	}
	cout << endl;
}

void release(Node& list) {
	while (list.next != 0) {
		Node* temp = list.next;
		list.next = list.next->next;
		delete temp;
	}
}

int main() {
	Node list(0, new Node(83, new Node(34, new Node(33, new Node(3, new Node(38, new Node(54)))))));
	display(list);
	sort(list);
	display(list);
	release(list);
	return 0;
}

在这里插入图片描述
2.有n个记录存储在带头结点的双向链表中,现用双向冒泡排序法对其按升序进行排序,请写出这种排序算法。(注:双向冒泡即相邻两趟排序向相反方向冒泡。)

#include <iostream>
using namespace std;

struct Node {
	int data;
	Node* prior;
	Node* next;
	Node(int data = 0, Node* prior = 0, Node* next = 0):
		data(data),
		prior(prior),
		next(next)
	{
		
	}
};

void add(Node& list, int num) {
	Node* node = new Node(num, &list, list.next);
	if (list.next == 0) {
		list.next = node;
	}
	else {
		list.next->prior = node;
		list.next = node;
	}
}

void display(Node& list) {
	Node* node = list.next;
	Node* pre = 0;
	while (node != 0)
	{
		cout << node->data << " ";
		pre = node;
		node = node->next;
	}
	cout << " <> ";
	while (pre != &list)
	{
		cout << pre->data << " ";
		pre = pre->prior;
	}
	cout << endl;
}

/* 题目要求的双向冒泡排序 */
void sort(Node& list) {
	Node* left = &list;
	Node* right = 0;
	while (left != right)
	{
		Node* node = left;
		while (node->next != right && left != right)
		{
			if (node->data > node->next->data) {
				Node* temp = node->next;
				node->next = node->next->next;
				if(node->next != 0)
					node->next->prior = node;
				temp->prior = node->prior;
				temp->next = node;
				node->prior->next = temp;
				node->prior = temp;
				continue;
			}
			node = node->next;
		}
		right = node;
		while (node->prior != left && left != right)
		{
			if (node->data < node->prior->data) {
				Node* temp = node->prior;
				node->prior = node->prior->prior;
				node->prior->next = node;
				temp->prior = node;
				temp->next = node->next;
				if(node->next != 0)
					node->next->prior = temp;
				node->next = temp;
				continue;
			}
			node = node->prior;
		}
		left = node;
	}
}


void release(Node& list) {
	while (list.next != 0) {
		Node* temp = list.next;
		list.next = list.next->next;
		delete temp;
	}
}

int main() {
	Node list;
	for (int i = 0; i < 20; i++) {
		add(list, 30);
		add(list, 0);
		add(list, 58);
		add(list, 56);
		add(list, 37);
		add(list, 91);
	}
	display(list);
	sort(list);
	display(list);
	release(list);
	return 0;
}

为了检测双向链表的正确性,display() 的时候正向反向都输了, 用 <>分隔。
在这里插入图片描述
3.设有顺序放置的 n n n个桶,每个桶中装有一粒砾石,每粒砾石颜色是红、白、蓝之一。求重新安排这此砾石,使得所有红色砾石在前,所有白色砾石居中,所有蓝色砾石在后,重新安排时对每粒砾石的颜色只能看一次,并用只允许交换操作为调整砾石的位置。

// (1) 据说可以用快排的的思想,从左往右找到第一个不为红的石头i, 从右往左找到第一个不为蓝的石头j,
// (2) 如果i = j = ‘白’,则i与i之后第一个不是白的交换,或j与j之前第一个不是白的交换
// (3) 如果i != j,  则交换 i 和 j 。
// (4) 重复 (1) 到 (3),直至砾石位置符合题意
// 太复杂了,略
// 有空再来填这个坑

4.编写算法,对 n n n个关键字取整数值的记录序列进行整理,以使所有关键字为负值为记录排在关键字为非负的记录之前,要求:
(1)采用顺序存储结构,至多使用一个记录的辅助空间;
(2)算法的时间复杂度为 O ( n ) O(n) O(n)

#include <iostream>
#include <vector>
using namespace std;

void arrange(vector<int>& records) {
	int i = 0;
	int j = records.size() - 1;
	while (i < j)
	{
		while (i < j && records[i] < 0) i++;
		while (i < j && records[j] >= 0) j--;
		if (i < j) {
			int t = records[i];
			records[i] = records[j];
			records[j] = t;
			i++;
			j--;
		}
	}
}


int main() {

	vector<int> records = { 7, 8, -7, 0, -3, 6, 2, -9, 0,-6, 6, 1 };
	arrange(records);
	for (int i = 0; i < records.size(); i++) {
		cout << records[i] << " ";
	}
	return 0;
}

在这里插入图片描述
5.借助快速排序的思想,在一组无序的记录中查找给定关键字的值等于 k e y key key的记录,设此记录存放于数组 r [ 1... n ] r[1...n] r[1...n]中。若查找成功,则返回在 r r r数组中的位置,否则显示"not find"信息。

#include <iostream>
#include <vector>
using namespace std;

/*题目要求的查找算法*/
int find(vector<int>& records, int key) {
	int i = 0;
	int j = records.size() - 1;
	while (i < j)
	{
		while (i < j && records[i] < key) i++;
		if (records[i] == key) return i; else i++;
		while (i < j && records[j] > key) j--;
		if (records[j] == key) return j; else j--;
	}
	return -1;
}


int main() {

	vector<int> records = { 7, 8, -7, 0, -3, 6, 2, -9, 0,-6, 6, 1 };
	int pos = find(records, 2);
	if (pos == -1) {
		cout << "not find" << endl;
	}
	else {
		cout << (pos) << endl;
	}
	for (auto& record : records) {
		cout << record << " ";
	}
	return 0;
}

在这里插入图片描述
6.有一种简单的排序算法,叫作计数排序。这种排序算法对一个待排序的的表进行排序,并将排序结果存放在另一个新的表中。必须注意的是,表中所有待排序的关键字互不相同,计数排序算法针对关键字表中的每一个记录,扫描待排序的表一趟,统计表中有多少个关键字比该记录的关键字小。假设针对某一个记录,统计数的计数值为 c c c,。 那么,这个记录在新的有序表中的合适位置就是 c c c.
(1)给出适合于计数排序的顺序表定义
(2)编写实现计数排序的算法
(3)对于有n个关键字的表,关键字的比较次数是多少?
(4)与简单选择排序相比,这种排序算法是否更好?为什么?

#include <iostream>
#include <vector>
using namespace std;


struct Node {
	int keyword;
	int value;
	Node(int keyword = 0, int value = 0) :
		keyword(keyword),
		value(value) {

	}
};

/* 题目要求的计数排序算法
	要求输入的关键字必须互不相同 */
vector<Node> sort(vector<Node> arr) {
	vector<Node> sorted(arr.size());
	for (int i = 0; i < arr.size(); i++) {
		int c = 0;
		for (int j = 0; j < arr.size(); j++) {
			if (arr[j].keyword < arr[i].keyword) {
				c++;
			}
		}
		sorted[c] = arr[i];
	}
	return sorted;
}



int main() {
	vector<Node> nodes = sort({ 9, 55, 34, 78, 7, 5, 11, 2, 30 });
	for (auto& node : nodes) {
		cout << node.keyword << " ";
	}
	cout << endl;
	return 0;
}

在这里插入图片描述
比较次数是 n 2 n^2 n2次,而选择排序一般只要比较 n ( n − 1 ) / 2 次 n(n-1)/2次 n(n1)/2, 因此这种排序算法没有更好。而且如果关键字重复,它也不支持。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值