将双向链表转化为二叉堆并有序输出

某公司的一道面试题,跪了,希望能学到东西!解决的问题是将双向链表有序输出,直接上代码,不懂的可以在下面提问,有问题希望高手能提出来,或者能进行优化的,感觉在输出的代码上写的不好,希望大牛帮忙看下。



/*问题:将一个双向链表有序的输出,平均时间
复杂度为nlogn,不能退化为n方,辅助空间大小为
O(1)

从上面的问题看来,只能使用堆排序对双向链表进行排序
输出,才能满足所有要有,所以我们
将双向链表转化为完全二叉树
然后进行堆排序
1,2,3,4,5,6
将双向链表的向前向后指针转化为
左指针和右指针

思路:
		  1
	  /		  \
     2         3
	/ \        / 
   4   5      6
   
*/

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


//双向链表的数据结构,这里使用就不使用模板了,直接使用int
typedef struct DoubleLinkList {
	int value;
	DoubleLinkList *pre;	//指向前一个结点
	DoubleLinkList *next;	//指向后一个结点
} * pDoubleLinkList;

//功能:建立双向链表
//输入:整形容器array
//输出:双向链表的头指针
//注:单元测试函数,时间复杂度不计入总时间复杂度
pDoubleLinkList createDoubleLinkList(vector<int> &array){
	if (array.empty())
		return NULL;
	pDoubleLinkList head = new DoubleLinkList;
	head->value = array[0];
	head->pre = head->next = NULL;
	pDoubleLinkList preNode = head;

	for( int i = 1; i != array.size(); i++){
		pDoubleLinkList newNode = new DoubleLinkList;
		newNode->value = array[i];
		newNode->pre = preNode;
		preNode->next = newNode;
		newNode->next = NULL;

		preNode = newNode;
	}
	return head;
}


//解决:将双向链表转化为二叉树
//输入:双向链表的头指针DoubleLinkList *head
//输出:二叉树的根结点指针,虽然这个结点依然是用双向链表的数据结构
//时间复杂度:n;
pDoubleLinkList DoubleLinkListToBinaryTree(pDoubleLinkList head){
	if (head == NULL)
		return NULL;

	//指向当前结点的指针
	pDoubleLinkList curNode = head;

	//指向下一结点的指针
	pDoubleLinkList nextNode = head->next;

	//指向当前结点子结点的指针
	pDoubleLinkList childNode = head->next;

	while (curNode != NULL){
		//对当结点的左右子结点进行赋值
		if (childNode == NULL){
			curNode->pre = NULL;
			curNode->next = NULL;
		}else{
			curNode->pre = childNode;
			childNode = childNode->next;
			curNode->next = childNode;
			if (childNode != NULL)
				childNode = childNode->next;
		}
		
		curNode = nextNode;
		if (nextNode != NULL)
			nextNode = nextNode->next;
	}
	return head;
}

//功能:对二叉树进行堆排序(小顶堆)
//输入:无序二叉树的根结点
//输出:二叉堆的根结点
//时间复杂度:nlogn

void HeapSort(pDoubleLinkList root){
	if (root == NULL)
		return ;
	HeapSort(root->pre);
	HeapSort(root->next);
	
	//如果这个结点有右子树
	if (root->next != NULL){
		//当前结点大于最小结点的值
		if (root->pre->value < root->next->value){
			if (root->value > root->pre->value){
				swap(root->value, root->pre->value);
				HeapSort(root->pre);
				}
		}else if (root->value > root->next->value){
			swap(root->value, root->next->value);
			HeapSort(root->next);
		}
	}else if (root->pre != NULL){ //如果当前结点没有右结点,但有左结点
		//当前结点大于左结点的值
		if (root->pre->value < root->value){
			swap(root->value, root->pre->value);
			HeapSort(root->pre);
		}
	}
}

//功能:返回二叉堆的最后一个结点
//输入:二叉堆的根结点,二叉堆的大小
//输出:二叉堆的最后一个结点指针
//时间复杂度:log(n)
pDoubleLinkList getEndNode(pDoubleLinkList *root, size_t length){
	if (*root == NULL || length == 0)
		return NULL;
	if (length == 1){
		pDoubleLinkList tmp = *root;
		*root = NULL;
		return tmp;
	}
	if (length == 2){
		pDoubleLinkList tmp = (*root)->pre;
		(*root)->pre = NULL;
		return tmp;
	}
	if (length == 3){
		pDoubleLinkList tmp = (*root)->next;
		(*root)->next = NULL;
		return tmp;
	}
	int i = 2;
	while(i++)
		if (pow(2, i) > length)
			break;
	int ipow = length - pow(2, i-1);
	if (ipow >= pow(2, i-2))
		return getEndNode(&(*root)->next, ipow);
	else
		return getEndNode(&(*root)->pre, ipow + 2);
}

//功能:将二叉堆有序输出
//输入:二叉堆的根结点pDoblueLinkList root
//输出:打印有序数组

void printfHeap(pDoubleLinkList root, size_t length){

	int i = length;
	while (root != NULL){
		HeapSort(root);
		cout<<root->value;
		pDoubleLinkList endNode = getEndNode(&root, i);
		i--;
		if (root != NULL)
			swap(root->value, endNode->value);
		delete(endNode);
	}
}


int main(int argc, char **argv){
	vector<int> vec;
	int tmp;
	while(cin>>tmp){
		vec.push_back(tmp);
	}
	pDoubleLinkList head = createDoubleLinkList(vec);
	pDoubleLinkList root = DoubleLinkListToBinaryTree(head);
	printfHeap(root, vec.size());
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值