双向链表(非循环)排序

双向链表的操作问题
Description
建立一个长度为n的带头结点的双向链表,使得该链表中的数据元素递增有序排列。(必须使用双向链表完成,数据类型为整型。)
Input
第一行:双向表的长度;
第二行:链表中的数据元素。
Output
输出双向链表中的数据元素的值。

Sample Input
1
2
3
10
2 4 6 3 5 8 10 21 12 9

Sample Output
2 3 4 5 6 8 9 10 12 21
方案一:不带头结点的双链表排序

链表的创建及元素的存储不难,难的是对元素的排序,对链表进行排序,就好做好对每一个节点的处理,这儿我采用的是插入排序,每次选出最小值的节点,将其从链表中删除,再将其按顺序插入到前面,依次实现排序。难点是对第一个节点的和最后一个节点的处理代码如下:

#include<iostream>
#include <stdlib.h>
using namespace std;
struct node
{
	int data;
	node *next,*pro;
};
int main()
{
	int n,i;
	cin>>n;
	node *head=NULL,*q,*p,*t;
	//创建双向链表,存储数据
	for(i=0;i<n;i++)
	{
		p=(node *)malloc(sizeof(node));
		p->next=p->pro=NULL;
		cin>>p->data;
		if(head==NULL)
		{
			q=head=p;
		}
		else
		{
			q->next=p;
			p->pro=q;
			q=p;
		}
	}
	//选择排序
	for(i=0;i<n;i++)
	{
		int min=0x3f3f3f3f;
		if(i==0)//第一次遍历从头结点遍历,之后每次遍历从未排序的第一个节点(q节点的下一个节点)遍历
			t=head,q=NULL;		//q记录排序好的节点的最后一个节点的位置,初始为NULL
		else
			t=q->next;
		while(t!=NULL)		//找出最小的节点
		{
			if(t->data<min)
			{
				min=t->data;
				p=t;		//用p指针记录当前未排序节点的最小值节点的位置
			}
			t=t->next;
		}

		//将p节点独立出来
		if(p->pro==NULL||p->pro==q)//p是未排序的第一个节点
		{
			q=p;					//后移一位即可
			continue;
		}
		else if(p->next==NULL)		//p是最后一个节点(要先判断是否是第一个未排序节点(处理该节点既是未排序节点又是尾节点))
			p->pro->next=NULL;		//先判断是首个未排序节点可以避免将已排序节点的后继指针赋值为空,造成链表从中间断裂
		else//中间的节点
		{
			p->pro->next=p->next;
			p->next->pro=p->pro;
		}

		//将p节点重新连接到前面
		if(i==0)		 //首个排序节点单独处理
		{
			head->pro=p; //第一个节点前继指针记录插入的p节点的位置
			p->next=head;//p节点后继指针记录第一个节点的位置
			p->pro=NULL; //p节点前继指针置空
			head=p;		 //头指针指向p
			q=p;		 //q指向p(为下次循环准备)
		}
		else
		{
			q->next->pro=p;
			p->next=q->next;
			q->next=p;
			p->pro=q;
			q=p;
		}
	}
	t=head;
	while(t!=NULL)
	{
		cout<<t->data<<" ";
		t=t->next;
	}
	return 0;
}

方案二:

带头结点的双链表排序,也是选择排序,非常方便

#include <iostream>
#include <stdlib.h>
using namespace std;
typedef struct node
{
	int data;
	node *next,*pri;
}LinkNode,*LInkList;
int main()
{
	LInkList head,p,t,q;
	head=(LInkList)malloc(sizeof(LinkNode));
	head->next=head->pri=NULL;
	int n,i;cin>>n;
	//创建双链表
	for(i=0;i<n;i++)
	{
		p=(LInkList)malloc(sizeof(LinkNode));
		p->next=p->pri=NULL;
		cin>>p->data;
		if(head->next==NULL)
			head->next=q=p;
		else
		{
			q->next=p;
			p->pri=q;
			q=p;
		}
	}
	//直接插入排序
	q=head->next->next;//q指向第一个节点的指针域(当不只有一个节点时指向第二个节点)
	head->next->next=NULL;//断开第一个节点和之后节点的联系
	while(q!=NULL)//依次取出断开链表的第一个结点向有序链表中插入
	{
		p=q->next;
		t=head;
		while(t->next!=NULL&&t->next->data<q->data)//找出插入点
			t=t->next;
		q->next=t->next;//插入
		t->next=q;
		q=p;//指向断开链表的下一个点(当前断开链表的第一个结点)
	}
	t=head;
	while(t->next!=NULL)
	{
		cout<<t->next->data<<' ';
		t=t->next;
	}
	return 0;
}

可以看出,加个头结点还是非常方便的= =

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值