链表:重新排列链表中的各节点【C语言,数据结构】(内含源代码)

 

目录

         题目:

题目分析:

我的思路解析:

正确思路解析:

源代码:

主程序:

头文件:

小结:


题目:

设线性表L=(a1,a2,^,an-1,an)采用带头节点的单链表保存,设计并实现一个空间复杂度为O(1)且时间上尽可能高效的算法,重新排列L中的各结点,得到线性表L'=(a1,an,a2,an-1,a3,an-2……).

题目分析:

1.空间复杂度为O(1),这个意思是,我们不能用到的工具空间不能随着输入链表长度大小而改变,代表不能复制一个反向链表再插入,这种做法是不行的,这个要求代表,我们只能通过工具指针来进行本题的操作。

2.时间上尽可能高效,代表,我们的指针要尽可能的减少遍历链表的次数,这里要注意的是,本题用的是单向链表,一旦前往下一个节点,就不能回头了,而观察题目发现,插入的元素是从后往前的,an an-1…,所以要怎么找到上一个节点,就会被这个时间高效给限制了。

我的思路解析:

在讲解正确解法前,我先讲一下我的“天才”解法,

用两个指针,一个指针不停的指着最后一个节点,一个指针指着他要插入的位置。

诶!这种方法是不是看起来简单又高效啊?那他执行起来是怎样的呢?

啊。。。可以看到,想法很美好,但是尾指针这个东西,不太好固定,每一次找他,都需要遍历一次数组,所以这个算法不够高效。

正确思路解析:

首先,第一次遍历:找到中间节点,把链表分成两半。

第二次遍历:逆转后半部分链表【在我之前的文章里有讲】

第三次遍历:把后面的链表插入前面的链表中。

这样整个题目只需要遍历三次,时间复杂度是O(n),非常高效!

源代码:

主程序:

#include "LinkList.h"	//头文件

Status ReSet_LinkList(LinkList);	//重新排列链表L
void GetHalfNODE(LinkList, LinkList*);	//返回中间节点
Status Reverse_LinkList(LinkList );	//逆转一张链表
Status Addin_LinkList(LinkList, LinkList);	//合并两张链表
void input(LinkList);		//根据输入创建


//*****main*****
int main() {
	LinkList La;
	InitList_LinkList(&La);	//原链表

	input(La);

	printf("Original LinkList: ");
	printlist_LinkList(La);

	printf("\nReSet LinkList: ");
	ReSet_LinkList(La);
	printlist_LinkList(La);

}//main

void input(LinkList La) {		//根据输入创建
	int n;
	ElemType e;

	printf("How long the LinkList will you take?\n");
	scanf("%d", &n);

	printf("Please input some integers to fill the LinkList.\n");
	for(int i = 1; i <= n; i++) {
		scanf("%d", &e.nub);
		ListInsert_LinkList(La, i, e);
	}
}//input


Status Reverse_LinkList(LinkList L) {	//逆转一张链表
	LinkList h, p, q, r;
	h = L;
	q = h->next;
	if(!q->next) {
		return OK;
	}
	p = q->next;
	q->next = NULL;
	while(p->next) {
		r = q;
		q = p->next;
		p->next = r;
		r = p;
		p = q;
		q = r;
	}
	h->next = p;
	p->next = q;

	return OK;
}	//Reverse_LinkList

void GetHalfNODE(LinkList la, LinkList* lb) {	//返回中间节点
	LinkList q = la, p = la;
	while(p->next) {
		q = q->next;
		p = p->next;
		if(p->next) {
			p = p->next;
		}
	}
	*lb = q;
}

Status Addin_LinkList(LinkList La, LinkList Lb) {	//合并两张链表
	LinkList q = La->next, p = Lb->next;
	LinkList toolq = q->next;
	Lb->next = NULL;
	while(p && q) {
		q->next = p;
		p = p->next;
		q->next->next = toolq;
		q = toolq;
		if(toolq) {
			toolq = toolq->next;
		}
	}
	return OK;
}

Status ReSet_LinkList(LinkList La) {	//重新排列链表L
	if(!La->next) {
		return OK;
	}
	if(!La->next->next) {
		return OK;
	}
	if(!La->next->next->next) {
		return OK;
	}
	LinkList Lb;

	GetHalfNODE(La, &Lb);

	Reverse_LinkList(Lb);

	Addin_LinkList(La, Lb);

	return OK;
}	//ReSet_LinkList

头文件:

#include  			//头文件
#include 
#include 
#include 
#include 
#define ERROR 0
#define OK 1	//函数结果状态代码
#define EQUAL 1
#define OVERFLOW -1
typedef int Status;	//Status 为函数返回值类型,其值为函数结果状态代码
struct NUBMER {
	int nub;
} stu[50];
typedef struct NUBMER ElemType;
//链表中数据元素类型
struct LNODE {
	ElemType data;
	struct LNODE *next;
};
typedef struct LNODE LNode;
typedef struct LNODE *LinkList;//线性表的链式存储结构的定义

Status InitList_LinkList(LinkList *); //带头结点单向链表L的初始化
Status GetElem_LinkList(LinkList, int, ElemType *);//获取链表L第i个元素
int ListLength_LinkList(LinkList);//求链表 L的长度
int EqualList(ElemType, ElemType); //判断数据元素 e1、e2是否相等
int LocateElem_LinkList(LinkList, ElemType, int);//在链表L中寻找第一个与
int Less_EqualList(ElemType, ElemType);//判断数据元素 el 是否小于 e2数据元素 e符合 type 关系的元素
Status ListInsert_LinkList(LinkList, int, ElemType);//在链表L的第 i个元素前插入新元素 e
void MergeList_LinkList(LinkList, LinkList, LinkList *); //例 2.2 已知单链线性
//表 La 和 Lb 的元素按值非递减排列,归并后得到新的单链线性表 Lc,元素也按值非递减排列
Status Destroy_LinkList(LinkList *);//销毁一张链表
void printlist_LinkList(LinkList); //输出链表L

Status InitList_LinkList(LinkList *L) { //带头结点单向链表L的初始化
	*L=(LNode *)malloc(sizeof(LNode));
	if(!L)
		exit(ERROR);
	(*L)->next=NULL;
	return OK;
}//InitList_LinkList
int ListLength_LinkList(LinkList L) { //求链表L的长度
	int j=0;
	while (L->next) {
		L=L->next;
		j++;
	}
	return j;
}//ListLength_LinkList
Status GetElem_LinkList(LinkList L, int i, ElemType *e) { //获取链表L的第i个元素
	LinkList p;
	int j;
	p=L->next;
	j=1;
	while (p&&jnext;
		++j;
	}
	if(!p||j>i)
		return ERROR;
	*e=p->data;
	return OK;
}//GetElem_LinkList


Status ListInsert_LinkList(LinkList L, int i, ElemType e) { //在链表 L的第i个元素前插入新元素。
	LinkList p, s;
	int j;
	p=L;
	j=0;
	while (p&&jnext;
		++j;
	}
	if(!p||j>i-1) return ERROR;
	s=(LinkList)malloc(sizeof(LNode));
	s->data=e;
	s->next=p->next;
	p->next=s;
	return OK;
}//ListInsert_LinkList
Status Destroy_LinkList(LinkList *L) { //销毁一张链表
	LinkList p, q;
	p=*L;
	q=p->next;
	while (p) {
		free(p);
		p=q;
		q=q->next;
	}
	return OK;
}//DestroyQueue

void printlist_LinkList(LinkList L) { //输出链表L
	int i;
	LinkList p;
	p=L;
	while (p->next) {
		p=p->next;
		printf("%d ", p->data.nub);
	}
	printf("\n");
}//printlist_LinkList

小结:

这道题主要考察的是算法,这算是算法的小试牛刀吧。

加油↖(^ω^)↗

你可能感兴趣的:(数据结构,C语言,链表,数据结构,c语言)