算法导论练习6.5-8 k路合并
题目:
请给出一个时间为O(nlgk)、用来将k个已排序链表合并为一个排序链表的算法。此处n为所有输入链表中元素的总数。(提示:用一个最小堆来做k路合并。
看到题目第个想到的是归并排序过程中的归并操作子过程,从头开始两两比较,找出最小的,然后接着往后比较,常用的是2路归并。而题目给的是k个已排好序的链表(k>=2)。如果没有提示,我半天不知道如何去实现,幸好提示说用最小堆来做k路合并,于是我想到可以这样做:创建一个大小为k的数组,将k个链表中的第一个元素依次存放到数组中,然后将数组调整为最小堆,这样保证数组的第一个元素是最小的,假设为min,将min从最小堆取出并存放到最终结果的链表中,此时将min所在链表的下一个元素到插入的最小堆中,继续上面的操作,直到堆中没有元素为止。举个例子如下图所示(只给出不部分操作):
最终结果如下图所示:
现在采用C++语言,借助STL实现此过程,链表采用list,最小堆中存放的是list的迭代器,表示list中元素的位置。完整程序如下:
#include <iostream>
#include <vector>
#include <list>
#include <iterator>
#include <cstdlib>
using namespace std; template<class T> class MinHeap
{
public:
MinHeap();
MinHeap(const size_t size);
~MinHeap();
T get_min() const;
void delete_min();
void insert_element(const T& e);
void adjust_min_heap(const size_t i);
size_t get_heap_size() const;
int compare(const T& t1,const T& t2);
private:
T *heap;
size_t heap_size;
}; template<class T>
MinHeap<T>::MinHeap():heap(NULL),heap_size(){} template<class T>
MinHeap<T>::MinHeap(const size_t size)
{
if(!heap)
delete [] heap;
heap = new T[size+];
heap_size = ;
} template<class T>
MinHeap<T>::~MinHeap()
{
if(!heap)
delete [] heap;
heap_size = ;
} template<class T>
T MinHeap<T>::get_min() const
{
if(heap_size > )
return heap[];
else
return T();
} template<class T>
void MinHeap<T>::delete_min()
{
if(heap_size > )
{
heap[] = heap[heap_size];
heap_size = heap_size - ;
adjust_min_heap();
}
else
{
cout<<"Error: the min heap is empty"<<endl;
}
} template<class T>
void MinHeap<T>::insert_element(const T& e)
{
size_t i,parent;
T temp;
heap_size = heap_size + ;
heap[heap_size] = e;
i = heap_size;
parent = i/;
while(i> && compare(heap[parent],heap[i]) > )
{
temp = heap[parent];
heap[parent] = heap[i];
heap[i] = temp;
i = parent;
parent = i/;
}
} template<class T>
void MinHeap<T>::adjust_min_heap(const size_t i)
{
size_t left,right,least;
T temp;
left = i*;
right = i*+;
if(left <= heap_size && compare(heap[left],heap[i]) < )
least = left;
else
least = i;
if(right <= heap_size && compare(heap[right],heap[least]) < )
least = right;
if(least != i)
{
temp = heap[least];
heap[least] = heap[i];
heap[i] = temp;
adjust_min_heap(least);
}
}
template<class T>
size_t MinHeap<T>::get_heap_size() const
{
return heap_size;
} template<class T>
int MinHeap<T>::compare(const T& t1,const T& t2)
{
return (*t1-*t2);
} const static int k = ; int main()
{ list<int> lists[k];
list<int>::iterator iters[k];
list<int> retlist;
list<int>::iterator retiter;
list<int>::iterator iter;
MinHeap<list<int>::iterator> minheap(k); //first list <12,24,52>
lists[].push_back();
lists[].push_back();
lists[].push_back();
cout<<"First list: ";
for(iter=lists[].begin();iter != lists[].end();++iter)
cout<<*iter<<"->";
cout<<"NULL"<<endl;
//second list <9,32>
lists[].push_back();
lists[].push_back();
cout<<"Second list: ";
for(iter=lists[].begin();iter != lists[].end();++iter)
cout<<*iter<<"->";
cout<<"NULL"<<endl;
//third list <34,42,78>
lists[].push_back();
lists[].push_back();
lists[].push_back();
cout<<"Third list: ";
for(iter=lists[].begin();iter != lists[].end();++iter)
cout<<*iter<<"->";
cout<<"NULL"<<endl;
iters[] = lists[].begin();
iters[] = lists[].begin();
iters[] = lists[].begin(); minheap.insert_element(iters[]);
minheap.insert_element(iters[]);
minheap.insert_element(iters[]); while(minheap.get_heap_size())
{
iter = minheap.get_min() ;
retlist.push_back(*iter);
minheap.delete_min();
++iter;
if(iter != lists[].end() && iter != lists[].end()
&&iter != lists[].end())
minheap.insert_element(iter);
}
cout<<"Merge the there list is: "<<endl;
for(retiter = retlist.begin();retiter!= retlist.end();retiter++)
cout<<*retiter<<"->";
cout<<"NULL"<<endl;
exit();
}
测试结果:
转自:http://www.cnblogs.com/Anker/archive/2013/01/24/2874569.html
我按照上面的写了代码,总是遇到错误说:在画红线的地方
if(it!=lists[0].end() && it!=lists[1].end() && it!=lists[2].end()):
总是报错:list iterator incompatible:
#include<iostream>
#include<string>
#include<list>
#include<algorithm>
using namespace std; int left(int i) { return *i;}
int right(int i){ return *i+;}
int parent(int i) { return i/;} template<class T>
class MinHeap
{
private:
T *heap;
int heapSize;
public: MinHeap(const int size);
~MinHeap(); void adjustMinHeap(int i); void insert(const T& e);
T extractMin();
T getMin();
void deleteMin(); void print();
int getHeapSize(){ return heapSize;}
int comp(const T& a,const T& b) { return (*a)-(*b);}
}; template<class T>
MinHeap<T>::MinHeap(const int size)
{
heap=new T[size+];
heapSize=;
}
template<class T>
MinHeap<T>::~MinHeap()
{
delete[] heap;
heapSize=;
} template<class T>
void MinHeap<T>::insert(const T& e)
{
heapSize++;
heap[heapSize]=e;//从这可以看出第0个不存
int i=heapSize;
int parentNode=parent(i);
while(i> && comp(heap[parentNode],heap[i])>) //注意,T里面的类型为Iter迭代器类型,不能是这么来比较heap[parentNode]>heap[i].
{
swap(heap[parentNode],heap[i]);
i=parentNode;
parentNode=parent(i);
}
} template<class T>
void MinHeap<T>::adjustMinHeap(int i)
{
int l=left(i);
int r=right(i);
int smallest;
if(l<=heapSize && comp(heap[l],heap[i])< )//l<=heapSize必须在前面,为什么,因为如果在后面,heap[l]将访问冲突
smallest=l;
else
smallest=i;
if(r<=heapSize && comp(heap[r],heap[smallest])<)
smallest=r; if(smallest!=i)
{
swap(heap[i],heap[smallest]);
adjustMinHeap(smallest);
}
}
template<class T>
T MinHeap<T>::extractMin()
{
T min=heap[];
heap[]=heap[heapSize];
heapSize--;
adjustMinHeap();
return min;
} template<class T>
T MinHeap<T>::getMin()
{
if(heapSize>)
return heap[];
else
return T();
} template<class T>
void MinHeap<T>::deleteMin()
{
heap[]=heap[heapSize];
heapSize--;
adjustMinHeap();
} template<class T>
void MinHeap<T>::print()
{
for(int i=;i<=heapSize;i++)
cout<<*heap[i]<<ends;
cout<<endl;
} //#define k 3
const int k=;
int main()
{
//验证MinHeap正确性
/*
MinHeap<int> heap(4);
heap.insert(4);
heap.insert(3);
heap.insert(1);
heap.insert(2);
heap.print(); //1 2 3 4
cout<<"min:"<<heap.extractMin()<<endl; //1
heap.print(); //2 4 3
*/ list<int> lists[k];
typedef list<int>::iterator Iter;
Iter iters[k]; MinHeap<Iter> minHeap(k); //first list<12,24,52>
lists[].push_back();
lists[].push_back();
lists[].push_back();
cout<<"First list: ";
Iter it;
for(it=lists[].begin();it!=lists[].end();it++)
cout<<*it<<"->";
cout<<"NULL"<<endl; //second list <9,32>
lists[].push_back();
lists[].push_back();
cout<<"Second list: ";
for(it=lists[].begin();it != lists[].end();++it)
cout<<*it<<"->";
cout<<"NULL"<<endl; //third list <34,42,78>
lists[].push_back();
lists[].push_back();
lists[].push_back();
cout<<"Third list: ";
for(it=lists[].begin();it != lists[].end();++it)
cout<<*it<<"->";
cout<<"NULL"<<endl; iters[]=lists[].begin();
iters[]=lists[].begin();
iters[]=lists[].begin(); minHeap.insert(iters[]);
minHeap.insert(iters[]);
minHeap.insert(iters[]);
minHeap.print();
list<int> retlist;
while(minHeap.getHeapSize()!=)//这个条件最开始没想到
{
it=minHeap.getMin();
retlist.push_back(*it);
minHeap.deleteMin();
++it; if(it!=lists[0].end() && it!=lists[1].end() && it!=lists[2].end())
{
minHeap.insert(it);
}
}
cout<<"Merge list:"<<endl;
for(it=retlist.begin();it!=retlist.end();it++)
cout<<*it<<"->";
cout<<"NULL"<<endl; }
搞了2-3个小时没有找到原因,暂时放一放。
算法导论练习6.5-8 k路合并的更多相关文章
- 使用最小堆来完成k路归并 6.5-8
感谢:http://blog.csdn.net/mishifangxiangdefeng/article/details/7668486 声明:供自己学习之便而收集整理 题目:请给出一个时间为O(nl ...
- 算法导论学习-Dynamic Programming
转载自:http://blog.csdn.net/speedme/article/details/24231197 1. 什么是动态规划 ------------------------------- ...
- 算法导论 6.5.9 堆实现K路归并问题
问题: 设计一个时间复杂度为O(NlogK)的算法,它能够将K个有序链表合并为一个有序链表,这里的N为所有输入链表包含的总的元素个数 分析: 该问题为经典的利用堆完成K路归并的问题: 当K个序列满足一 ...
- 算法导论第十八章 B树
一.高级数据结构 本章以后到第21章(并查集)隶属于高级数据结构的内容.前面还留了两章:贪心算法和摊还分析,打算后面再来补充.之前的章节讨论的支持动态数据集上的操作,如查找.插入.删除等都是基于简单的 ...
- B树——算法导论(25)
B树 1. 简介 在之前我们学习了红黑树,今天再学习一种树--B树.它与红黑树有许多类似的地方,比如都是平衡搜索树,但它们在功能和结构上却有较大的差别. 从功能上看,B树是为磁盘或其他存储设备设计的, ...
- 基本数据结构(2)——算法导论(12)
1. 引言 这一篇博文主要介绍链表(linked list),指针和对象的实现,以及有根树的表示. 2. 链表(linked list) (1) 链表介绍 我们在上一篇中提过,栈与队 ...
- 堆排序与优先队列——算法导论(7)
1. 预备知识 (1) 基本概念 如图,(二叉)堆是一个数组,它可以被看成一个近似的完全二叉树.树中的每一个结点对应数组中的一个元素.除了最底层外,该树是完全充满的,而且从左向右填充.堆的数组 ...
- [算法导论]二叉查找树的实现 @ Python
<算法导论>第三版的BST(二叉查找树)的实现: class Tree: def __init__(self): self.root = None # Definition for a b ...
- MIT算法导论——第五讲.Linear Time Sort
本栏目(Algorithms)下MIT算法导论专题是个人对网易公开课MIT算法导论的学习心得与笔记.所有内容均来自MIT公开课Introduction to Algorithms中Charles E. ...
随机推荐
- EC读书笔记系列之6:条款11 在operator=中处理自我赋值
记住: ★确保当对象自我赋值时operator=有良好行为.有三种方法:比较“来源对象”和“目标对象”的地址.精心周到的语句顺序.以及copy-and-swap技术 ★确定任何函数若操作一个以上对象, ...
- BZOJ 2707: [SDOI2012]走迷宫( tarjan + 高斯消元 )
数据范围太大不能直接高斯消元, tarjan缩点然后按拓扑逆序对每个强连通分量高斯消元就可以了. E(u) = 1 + Σ E(v) / degree(u) 对拍时发现网上2个程序的INF判断和我不一 ...
- 高效CSS开发核心要点摘录
做网站的,我们都知道尽量减少请求数,压缩CSS代码量,使用高效CSS选择符等方式可以来提高网站的载入速度和访问速度,也就是优化网站的性能. 下面分析了一些CSS的书写方式,很多都是我们知道并且正在使用 ...
- linux 程序运行监控
一 . 使用supervise 是daemon-tools 的一个功能,系统的守护进程.在进程挂掉的时候可以自动重启. 二 安装 wget http://cr.yp.to/daemontools/ ...
- 基于ArcEngine的影像数据管理系统研制
基于ArcEngine的影像数据管理系统研制 如果批处理,速度很慢,效率低. 详情如下: 分成很多小块的影像数据,要达到连续显示的效果,并导入ArcSDE for SQL Server中以方便管理.在 ...
- python 类型转换函数
python提供了一些可将某个值从一种类型转换为另一种类型的内置函数. 1. int函数可以把任何可以转换为整型的值转换为整型.int可以将浮点数转换为整数,但不会做四舍五入操作,而是直接丢弃小数部分 ...
- The Euler function(欧拉函数)
The Euler function Time Limit : 2000/1000ms (Java/Other) Memory Limit : 32768/32768K (Java/Other) ...
- android 屏幕适配问题【转】
如何将一个应用程序适配在不同的手机上,虽然这不算是一个技术问题,但是对于刚刚做屏幕的开发人员来说,还真不是一件多么简单的事情. 首先:你需要在AndroidManifest.xml文件的<m ...
- JS学习笔记(二)运算符和流程控制语句
js中的运算符和流程控制,循环,判断语句都和C#基本一致,但又有其独特的运算符. typeof运算符 获得数据的数据类型,如number,string等.语法: string typeof(变量); ...
- 性能优化工具---iostat
Iostat (参考 man iostat) 可选项: -c为汇报CPU的使用情况: -d为汇报磁盘的使用情况: -k表示每秒按kilobytes字节显示数据: -t为打印汇报的时间: -v表示打印出 ...