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(n−1)/2次, 因此这种排序算法没有更好。而且如果关键字重复,它也不支持。