王道数据结构链表算法整理

1.设计一个递归算法,删除不带头结点的单链表L中所有值为x的节点。
void deleteXNode(LinkList &head, ElemType x) {
	if (head == NULL) return;
	if (head->data != x) {
		return deleteXNode(head->next, x);
	}
	LNode* q = head;
	head = head->next;
	delete q;
	return deleteXNode(head, x);
}

2.在带头结点的单链表工中,删除所有值为ⅹ的结点,并释放其空间,假设值为ⅹ的结点不唯一,试编写算法以实现上述操作。

// 双指针
LinkList deleteXNode(LinkList &head, ElemType X) {
	LinkList p = head->next;
	LinkList q = head;
	while (p != NULL) {
		if (p->data == X) {
			LNode* d = p;
			q->next = p->next;
			p = p->next;
			delete d;
		}
		else {
			q = p;
			p = p->next;
		}
	}
	return head;
}

 3.设 L 为带头结点的单链表,编写算法实现从尾到头反向输出每个结点的值。

// 先递归,后输出
void reversePrint(LinkList L) {
	if (L->next != NULL) {
		reversePrint(L->next);
	}
	cout << L->data<<" ";
}

4.试编写在带头结点的单链表 L 中删除一个最小值结点的高效算法(假设最小值结点是唯一的)。

// 双指针的典型操作
void delMinNode(LinkList& head) {
	LNode* p = head->next;
	LNode* q = head;
	LNode* Minq = q, * Minp = p;
	while (p != NULL) {
		if (p->data < Minp->data) {
			Minp = p;
			Minq = q;
		}
		else {
			q = p;
			p = p->next;
		}
	}
	LNode* X = Minp;
	Minq->next = Minp->next;
	Minp = Minp->next;
	delete X;
}

5.试编写算法将带头结点的单链表就地逆置,所谓“就地”是指辅助空间复杂度为 O(1)

// 第一种 类似交换 指针反向
void reverseList(LinkList& head) {
	LNode* pre, * p = head->next, * r = p->next;
	p->next = NULL;
	while (r != NULL) {
		pre = p;
		p = r;
		r = r->next;
		p->next = pre;
	}
	head->next = p;
}

// 第二种 头插法
void reverseList2(LinkList L){
	LNode *p=L->next,*q;
	L->next=NULL;
	while(p){
		q=p->next;
		p->next=L->next;
		L->next=p;
		p=q;
	}
}

6. 有一个带头结点的单链表 L,设计一个算法使其元素递增有序。

//将链表的头结点后第一个节点与后面的节点断开,然后遍历节点重新在合适的位置插入
void sortList(LinkList &head) {
	LinkList p = head->next;
	LinkList q = p->next;
	LinkList pre;
	p->next = NULL;
	p = q;
	while (q != NULL) {
		p = q->next;
		pre = head;
		for (; pre->next != NULL && (pre->next->data < q->data); pre = pre->next);
		q->next = pre->next;
		pre->next = q;
		q = p;
	}
}

7. 设在一个带表头结点的单链表中所有元素结点的数据值无序,试编写一个函数,删除表中所有介于给定的两个值(作为函数参数给出)之间的元素的元素(若存在)。

void delBetweenAB(LinkList& head, int A, int B) {
	if (A > B) {
		return;
	}
	LinkList  pre = head;
	LinkList p = pre->next;
	while (p != NULL) {
		if (pre->next->data >= A && pre->next->data <= B) {
			LNode* del = p;
			pre->next = p->next;
			p = p->next;
			delete del;
		}
		else {
			pre = p;
			p = p->next;
		}
	}
}

8.给定两个单链表,编写算法找出两个链表的公共结点

// Y型 若包含公共节点,则公共节点之后的节点的肯定都是公共节点
// 长链表遍历到与短链表相同长度的位置 开始比较
LinkList FindCommonList(LinkList A,LinkList B) {
	int LenA = getLenth(A), LenB = getLenth(B), DiffLen=abs(LenA-LenB);
	LinkList LongList, ShortList;
	if (LenA > LenB) {
		LongList = A->next;
		ShortList = B->next;
	}
	else {
		LongList = B->next;
		ShortList = A->next;
	}
	while (DiffLen--) {
		LongList = LongList->next;
	}
	while (LongList != NULL) {
		if (LongList == ShortList) {
			return LongList;
		}
		else {
			LongList = LongList->next;
			ShortList = ShortList->next;
		}

	}
}

int getLenth(LinkList L) {
	int len = 0;
	LinkList p = L->next;
	while (p != NULL) {
		p = p->next;
		len++;
	}
	return len;
}

9.给定一个带表头结点的单链表, 设head为头指针, 结点结构为(data, next), data 为整型元素,next为指针, 试写出算法:按递增次序输出单链表中各结点的数据元素, 并释放结点所占的存储空间(要求 : 不允许使用数组作为辅助空间)

// 两层遍历即可
void sortPrintAndFree(LinkList &head) {
	while (head ->next!= NULL) {
		LNode* p = head->next;
		LNode*  minpre = head;
		while (p->next != NULL) {
			if (p->next->data < minpre->next->data) {
				minpre = p;
			}
			else {
				p = p->next;
			}
		}
		LNode* del = minpre->next;
		minpre->next = del->next;
		cout <data << " ";
		delete del;
	}
	cout << endl;
}

10.将一个带头结点的单链表A分解为两个带头结点的单链表A和B, 使得A表中含有原表 中序号为奇数的元素, 而B表中含有原表中序号为偶数的元素, 且保持其相对顺序不变

void split(LinkList &head) {
	LinkList B = (LinkList)malloc(sizeof(LNode));
	B->next = NULL;
	LinkList p = head->next;
	LinkList pre = head;
	LinkList Bp = B;
	int i = 0;
	while (p != NULL) {
		i++;
		if (i % 2 == 0) {
			LNode* q = p;
			Bp->next = q;
			Bp = q;
			pre->next = p->next;
		}else {
			pre = p;
			p = p->next;
		}
	}
	cout << "A:" << endl;
	PrintList(head);
	cout << "B:" << endl;
	PrintList(B);
}
11.设C = { a1,b1,a2,b2,…,an,bn }为线性表, 采用带头结点的hc单链表存放, 设计一个就地算法, 将其拆分为两个线性表, 使得A = { a1,a2…,an }, B = { bn,…,b2,b1 }
// B改头插
void splitting(LinkList &head) {
	LinkList B = (LinkList)malloc(sizeof(LNode));
	B->next = NULL;
	LinkList p = head->next;
	LinkList pre = head;
	LinkList Bp=B;
	int i = 0;
	while (p != NULL) {
		i++;
		if (i % 2 == 0) {
			LNode* q = p;
			pre->next = p->next;
			q->next = Bp->next;
			Bp->next = q;
			p = pre->next;
		}
		else {
			pre = p;
			p = p->next;
		}
	}
}
12.在一个递增有序的线性表中有数值相同的元素存在。若存储方式为单链表, 设计算法去掉数值相同的元素, 使表中不再有重复的元素, 例如(7, 10, 10, 21, 30, 42, 42, 42, 51, 70)将变为(7, 10, 21, 30, 42, 51, 70)
void deDuplication(LinkList& head) {
	LinkList p = head->next;
	LinkList pre = head;
	while (p != NULL) {
		if (p->data == pre->data) {
			LNode* del = p;
			pre->next = p->next;
			delete del;
			p = pre->next;
		}
		else {
			pre = p;
			p = p->next;
		}
	}
}
13.假设有两个按元素值递增次序排列的线性表, 均以单链表形式存储。请编写算法将这两个单链表归并为一个按元素值递减次序排列的单链表, 并要求利用原来两个单链表的结点存放归并后的单链表
void consolidation(LinkList& A, LinkList& B) {
	LinkList p1 = A->next, p2 = B->next;
	LinkList pre1 = A, pre2 = B;
	pre1->next = NULL;
	while (p1 != NULL && p2 != NULL) {
		if (p1->data <= p2->data) {  // 将x节点头插到A中
			LinkList r = p1->next;
			LNode* x = p1;
			x->next = pre1->next;
			pre1->next = x;
			p1 = r;
		}
		else {
			LinkList r = p2->next;
			LNode* x = p2;
			x->next = pre1->next;
			pre1->next = x;
			p2 = r;
		}
	}
	//将剩余的接上
	while (p1 != NULL) {
		LinkList r = p1->next;
		LNode* x = p1;
		x->next = pre1->next;
		pre1->next = x;
		p1 = r;
	}
	while (p2 != NULL) {
		LinkList r = p2->next;
		LNode* x = p2;
		x->next = pre1->next;
		pre1->next = x;
		p2 = r;
	}
}
14.设A和B是两个单链表(带头结点), 其中元素递增有序。设计一个算法从A和B中的公共元素产生单链表C, 要求不破坏A、B的结点
LinkList findComonList(LinkList& A, LinkList& B) {
	LinkList pa = A->next, pb = B->next;
	LinkList C= (LinkList)malloc(sizeof(LNode));
	C->next = NULL;
	LinkList pc = C;
	while (pa && pb) {
		if (pa->data < pb->data) {
			pa = pa->next;
		}
		else if (pa->data > pb->data) {
			pb = pb->next;
		}
		else{ // 相等
			LNode* r = (LNode*)malloc(sizeof(LNode));
			r->data = pa->data;
			r->next = NULL;
			pc->next = r;
			pc = r;
			pa = pa->next;
			pb = pb->next;
		}
	}
	return C;
}
15.已知两个链表A和B分别表示两个集合, 其元素递增排列。编制函数, 求A与B的交集, 并存放于A链表中
// 与上题类似
void getComonListToA(LinkList& A, LinkList& B) {
	LinkList pa = A->next, pb = B->next;
	LinkList pre = A;
	pre->next = NULL;
	while (pa && pb) {
		if (pa->data < pb->data) {
			pa = pa->next;
		}
		else if (pa->data > pb->data) {
			pb = pb->next;
		}
		else { // 相等
			LNode* r = (LNode*)malloc(sizeof(LNode));
			r->data = pa->data;
			r->next = NULL;
			pre->next = r;
			pre = r;
			pa = pa->next;
			pb = pb->next;
		}
	}
}
16.两个整数序列A = a1,a2,a3…, an和B = b1, b2, b3, …, bn已经存入两个单链表中, 设计个算法, 判断序列B是否是序列A的连续子序列
// 用的暴力
bool Subsequences(LinkList& A, LinkList& B) {
	LinkList pa = A->next, pb = B->next, pre = pa;
	while (pa && pb) {
		if (pa->data == pb->data) {
			pa = pa->next;
			pb = pb->next;
		}
		else {
			pre = pre->next;
			pa = pre;
			pb = B->next;
		}
	}
	if (!pb)
		return true;
	else
		return false;
}

17.设计一个算法用于判断带头结点的循环双链表是否对称

bool palindrome(LinkList& A) {
	LinkList P = A->next;
	LinkList Q = A->prior;
	for (; P->data == Q->data && (P->prior != Q && P != Q ); P = P->next, Q = Q->prior);
	if (P->prior == Q || P == Q)
		return true;
	return false;

}

18.有两个循环单链表, 链表头指针分别为h1和h2, 编写一个函数将链表h2链接到链表h1之后, 要求链接后的链表仍保持循环链表形式

LinkList merger(LinkList &A,LinkList &B) {

	LinkList pa = A->next;
	LinkList pb = B->next;
	for (; pa->next != A; pa = pa->next);
	for (; pb->next != B; pb = pb->next);
	pa->next = B->next;
	pb->next = A;
	return A;
}

19.设有一个带头结点的循环单链表,其结点值均为正整数。设计一个算法,反复找出单链表中结点值最小的结点并输出,然后将该结点从中删除, 直到单链表空为止,再删除表头结点。

void delMinPrint(LinkList& A) {
	LinkList p = A->next;
	LinkList pre = A;
	LNode* minp = p;
	LNode* minpre = A;
	while (A->next != A)
	{
		p = A->next;
		pre = A;
		minp = p;
		minpre = pre;
		while (p != A) {
			if (p->data < minp->data) {
				minp = p;
				minpre = pre;
			}
			else {
				pre = p;
				p = p->next;
			}
		}
		minpre->next = minp->next;
		cout << minp->data<<" ";
		delete minp;
	}
}

20.

设头指针为L的带有表头结点的非循环双向链表, 其每个结点中除有pred(前驱 指针)、data(数据)和next(后继指针)域外, 还有一个访问频度域freq。

在 链表被启用前, 其值均初始化为零。每当在链表中进行一次 Locate(L, x)运算时 令元素值为ⅹ的结点中freq域的值增1, 并使此链表中结点保持按访问频度非增 (递减)的顺序排列, 同时最近访问的结点排在频度相同的结点前面, 以便使频繁 访问的结点总是靠近表头。

试编写符合上述要求的 Locate(L, x)运算的算法, 该 运算为函数过程, 返回找到结点的地址, 类型为指针型

LNode* Locate(LinkList L, int x) {
	LinkList p = L->next, pre = L;
	for (; p && p->data != x; p = p->next);
	if (!p) {
		cout << "x不存在" << endl;
		return NULL;
	}
	else {
		(p->freq)++;
		p->prior->next = p->next;
		p->next->prior = p->prior;
		pre = p->prior;
		for (; pre != L && pre->freq <= p->freq; pre = pre->prior);
		p->next = pre->next;
		pre->next->prior = p;
		p->prior = pre;
		pre->next = p;
	}
	return p;
}

21.

已知一个带有表头结点的单链表,结点结构为
       data   link
假设该链表只给出了头指针1ist。在不改变链表的前提下, 请设计一个尽可能高效的算法, 查找链表中倒数第k个位置上的结点(k为正整数)。若查找成功, 算法输出该结
点的data域的值, 并返回1; 否则, 只返回0。
1)描述算法的基本设计思想
2)描述算法的详细实现步骤
3)根据设计思想和实现步骤, 采用程序设计语言描述算法(使用C、C++或Java语实现), 关键之处请给出简要注释
// 双指针 快指针先走k 后双指针一块走
int search_K(LinkList L, int k) {
	int count = 0;
	LinkList p = L->next, pk = p;
	while (p) {
		if (count < k)
			count++;
		else
			pk = pk->next;
		p = p->next;
	}
	if (count < k) {
		return 0;
	}
	else {
		cout << pk->data;
		return 1;
	}
}

22.

假定采用带头结点的单链表保存单词,当两个单词有相同的后缀时,可共享相同的后缀存储空间,例如,“loading”和 “being”的存储映像如下图所示。设str1和str2分别指向两个单词所在单链表的头结点, 链表结点结构为data,next,请设计一个时间上尽可能高效的算法, 找出由Str1和str2所指向两个链表共同后缀的起始位置(如图中字符i所在结点的位置p)。要求
1)给出算法的基本设计思想
2)根据设计思想, 采用C或C++或Java语言描述算法, 关键之处给出注释
3)说明你所设计算法的时间复杂度
// 同求交集
LinkList findCom(LinkList A,LinkList B) {
	int len1 = getlen(A), len2 = getlen(B), Diff = abs(len1 - len2);
	LinkList longlist, shortlist;
	if (len1 > len2) {
		longlist = A->next;
		shortlist = B->next;
	}
	else {
		longlist = B->next;
		shortlist = A->next;
	}
	while (Diff--)
		longlist = longlist->next;
	while (longlist) {
		if (longlist == shortlist)
			return longlist;
		longlist = longlist->next;
		shortlist = shortlist->next;
	}
}

int getlen(LinkList L) {
	int len = 0;
	while (L != NULL) {
		L = L->next;
		len++;
	}
	return len;
}

23.

用单链表保存m个整数, 结点的结构为[data][1ink], 且 |data| ≤ n(n为正整数)。现要求设计一个时间复杂度尽可能高效的算法, 对于链表中data的绝对值相等的结点, 仅保留第一次出现的结点而删除其余绝对值相等的结点。要求
1)给出算法的基本设计思想
2)使用C或C + 语言, 给出单链表结点的数据类型定义
3)根据设计思想, 采用C或C + 语言描述算法, 关键之处给出注释
4)说明你所设计算法的时间复杂度和空间复杂度
void de_duplication(LinkList L) {
	int bos[n+1] = {0};
	LinkList p = L->next, pre = L;
	while(p) {
		if (!box[abs(p->data)]) {
			box[abs(p->data)] = 1;
			pre = p;
			p = p->next;
		}
		else {
			LNode* r = p->next;
			pre->next = p->next;
			delete p;
			p = r;
		}
	}
}

24.设计一个算法完成以下功能:判断一个链表是否有环, 如果有, 找出环的入口点并返回,否则返回NULL

// 快满指针
LNode* findCycle(LinkList L) {
	LinkList fast = L, slow = L;
	while (slow != NULL && fast->next != NULL) {
		slow = slow->next;
		fast = fast->next->next;
		if (slow == fast)
			break;
	}
	if (slow == NULL || (fast->next == NULL))
		return NULL;
	LinkList p = L, q = slow;
	for (; p != q; p = p->next, q = q->next);
	return q;
 }
25.
设线性表L = (a1,a2, a3,…, an-2,an-1,an)采用带头结点的单链表保存请设计一个空间复杂度为O(1)且时间上尽可能高效的算法, 重新排列 L中的各结点, 得
到线性表L = (a1, an,a2,an-1, a3, an-2…)。要求
1)给出算法的基本设计思想
2)根据设计思想, 采用C或C艹语言描述算法, 关键之处给出注释
3)说明你所设计的算法的时间复杂度
// 双指针 找到n/2位置
void customSort(LinkList& L) {
	LinkList p, q, r, s;
	p = q = L;
	while (q->next != NULL) {
		p = p->next;
		q = q->next;
		if (q->next != NULL) {
			q = q->next;
		}
	}
	q = p->next;
	p->next = NULL;
	while (q != NULL) {
		r = q->next;
		q->next = p->next;
		p->next = q;
		q = r;
	}
	s = L->next;
	q = p->next;
	p->next = NULL;
	while (q != NULL) {
		r = q->next;
		q->next = s->next;
		s->next = q;
		s = q->next;
		q = r;
	}

}

你可能感兴趣的:(数据结构,王道,数据结构,链表,算法)