【王道408数据结构】线性表习题

Seqlist

  • P18开始的习题
  • 算法真美妙
  • 不保证正确,欢迎讨论,本质是伪代码,只是一个思路,实现还需要考虑一些细节


1. 删除最小元素

从顺序表中删除具有最小值的元素( 假设唯一)并由函数返回被删元素的值。空出的位置由最后一个元素填补,若顺序表为空,则显示出错信息并退出运行。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>

using namespace std;

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	size_t size;
	size_t capacity;
}SL;

//算法思路:遍历顺序表,如果比value小,value就等于它,并且记录该数据的下标,最后将最后一个字符与之交换
bool Del_Min(SL& ps, SLDateType& value)
{
	//如果为空,返回错误
	if (ps.size == 0)
	{
		return false;
	}
	//记录数组下标
	size_t index = 0;
	for (size_t i = 0; i < ps.size; i++)
	{
		//如果比value小赋值给value
		if (value > ps.a[i])
		{
			value = ps.a[i];
			index = i;
		}
	}
	//交换
	//ps.a[index] = ps.a[ps.size - 1];
	//这里template <class T> void swap (T& a, T& b);
	swap(ps.a[index], ps.a[ps.size - 1]);
	ps.size--;
	return true;
}

2. 顺序表逆置

设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为0(1)。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>

using namespace std;

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	size_t size;
	size_t capacity;
}SL;

//算法思路:两个指针指向left和right,向中间首尾交换,直到相遇
void Reverse(SL& ps)
{
	size_t left = 0;
	size_t right = ps.size - 1;

	//直到中间相等或者right比left大退出循环
	while (left < right)
	{
		//交换
		swap(ps.a[left], ps.a[right]);
		//向中间移动
		left++;
		right--;
	}
}

3. 删除所有值为x的元素

对长度为n的顺序表L,编写一个时间复杂度为0(n)、空间复杂度为0(1)的算法,该算法删除线性表中所有值为x的数据元素。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>

using namespace std;

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	size_t size;
	size_t capacity;
}SL;

//算法思路:遍历,一个指针遇到x停下,另一个指针寻找不是x元素的数值,将该值赋值给该位置。
void Del_Value(SL& ps, SLDateType x)
{
	//记录可以替换的位置
	int cur = 0;
	//寻找x元素
	int index = 0;

	while(index < ps.size -1)
	{
		if (ps.a[index] != x)
		{
			ps.a[cur] = ps.a[index];
			cur++;
		}
		//遇到相等的时候cur停止移动,而index继续右移动,将数值赋值给cur(覆盖掉x)
		index++;
	}

	ps.size = cur;
}

4. 删除范围元素

从有序顺序表中删除其值在给定值s与t之间(要求s<t)的所有元素,若s或t不合理或顺序表为空,则显示出错信息并退出运行。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>

using namespace std;

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	size_t size;
	size_t capacity;
}SL;

/*算法思路:
和第三题差不多,遇到s-t范围内k++,
范围外将其赋值给该位置减去k,最终数组最后k个数就是s-t中数组
*/

bool Del_ValueRange(SL& ps, const SLDateType& s, const SLDateType& t)
{
	//s和t不合法,数组为空
	if (s >= t || ps.size == 0)
	{
		return false;
	}

	size_t k = 0;
	for (size_t i = 0; i < ps.size; i++)
	{
		if (ps.a[i] > s && ps.a[i] < t)
		{
			k++;
		}
		else
		{
			ps.a[i - k] = ps.a[i];
		}
	}

	ps.size -= k;

	return true;
}

5. 删除范围元素(与第四题相似)

从顺序表中删除其值在给定值s与t之间(包含s和t,要求s<t)的所有元素,若s或t不合理或顺序表为空,则显示出错信息并退出运行。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>

using namespace std;

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	size_t size;
	size_t capacity;
}SL;

/*算法思路:
和第三题差不多,遇到s-t范围内k++,
范围外将其赋值给该位置减去k,最终数组最后k个数就是s-t中数组
*/

bool Del_ValueRange(SL& ps, const SLDateType& s, const SLDateType& t)
{
	//s和t不合法,数组为空
	if (s >= t || ps.size == 0)
	{
		return false;
	}

	size_t k = 0;
	for (size_t i = 0; i < ps.size; i++)
	{
		if (ps.a[i] >= s && ps.a[i] =< t)
		{
			k++;
		}
		else
		{
			ps.a[i - k] = ps.a[i];
		}
	}

	ps.size -= k;

	return true;
}

6. 删除重复元素

从有序顺序表中删除所有其值重复的元素,使表中所有元素的值均不同。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
using namespace std;

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	size_t size;
	size_t capacity;
}SL;

/*算法思路:
记录cur和index,index记录寻找和cur不同的数组元素下标;
如果cur等于index,index++;
如果cur不等于index,cur++,cur=index,index++;
index无论在哪种情况都需要++,所以index可以为for循环的i
*/

void Del_Dup_Ele(SL& ps)
{

	size_t cur = 0;

	for (size_t i = 0; i < ps.size - 1; i++)
	{
		if (ps.a[cur] != ps.a[i])
		{
			cur++;
			ps.a[cur] = ps.a[i];
		}
	}

	ps.size = cur;

}

7. 合并两个有序数组

将两个有序顺序表合并为一个新的有序顺序表,并由函数返回结果顺序表。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
using namespace std;

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	size_t size;
	size_t capacity;
}SL;

/*算法思路:
ps3存放,分别遍历ps1和ps2,小的先赋给ps3
*/

bool Merge_Ordered_List(const SL& ps1, const SL& ps2, SL& ps3)
{
	if (ps1.size + ps2.size > ps3.size)
	{
		return false;//放不下
	}

	int i = 0;
	int j = 0;
	int k = 0;

	while (i < ps1.size && j < ps2.size)
	{
		if (ps1.a[i] < ps2.a[j])
		{
			ps3.a[k++] = ps1.a[i++];
		}
		else
		{
			ps3.a[k++] = ps2.a[j++];
		}
	}

	while (i < ps1.size)
	{
		ps3.a[k++] = ps1.a[i++];
	}

	while (j < ps2.size)
	{
		ps3.a[k++] = ps2.a[j++];
	}

	ps3.size = k;
	return true;
}

8. 两个链表换位

已知在一维数组A[m + n]中依次存放两个线性表(an, a2, a… am)和(b, b2, b3…… bn)。编写一
个函数,将数组中两个顺序表的位置互换,即将(b1, b2, b3… bn,)放在(a1, a2, a3…… am)的前面。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
using namespace std;

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	size_t size;
	size_t capacity;
}SL;

/*
算法思路:
a表逆置,b表逆置,整个链表逆置
*/

void Reverse_List(SLDateType* a, int sz)
{
	int begin = 0;
	int end = sz - 1;
	while (begin < end)
	{
		swap(a[begin], a[end]);
	}
}

void Dul_List_Swap_Position(SL& pl, int m, int n)
{
	Reverse_List(pl.a, m);
	Reverse_List(pl.a + m, n);
	Reverse_List(pl.a, m + n);

}

9. 二分查找

线性表(a1, a2, a3…… an)中的元素递增有序且按顺序存储于计算机内。要求设计一个算法,完成用最少时间在表中查找数值为x的元素,若找到,则将其与后继元素位置相交换,若找不到,则将其插入表中并使表中元素仍递增有序。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
using namespace std;

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	size_t size;
	size_t capacity;
}SL;

/*
算法思路:
寻找中间数,如果比x大找右边,比x小,找左边
在按照这个思路继续查找
*/


void Binary_Search(SL& pl, SLDateType x)
{
	int left = 0;
	int right = pl.size;
	int mid = (left + right) / 2;

	while (left <= right)
	{
		if (x > pl.a[mid])
		{
			left = mid + 1;
			mid = (left + right) / 2;
		}

		if (x < pl.a[mid])
		{
			right = mid - 1;
			mid = (left + right) / 2;
		}

		//找到了
		if (pl.a[mid] == x)
		{
			break;
		}
	}
	
	if (pl.a[mid] == x && mid != pl.size - 1)
	{
		swap(pl.a[mid], pl.a[pl.size - 1]);
	}
	else
	{
		for (int i = pl.size - 1; i > mid ; i--)
		{
			pl.a[i + 1] = pl.a[i];
		}
		pl.a[mid + 1] = x;
	}
}

10. [2010统考真题]循环移动

设将n (n> 1)个整数存放到一维数组R中。设计一个在时间和空间两方面都尽可能高效的算法。将R中保存的序列循环左移p(0<p<n)个位置,即将R中的数据由(X0, X1, Xn-1)变换为(Xp, Xp+1,……X0, X1,Xp-1)

要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用C或C+或Java语言描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
using namespace std;

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	size_t size;
	size_t capacity;
}SL;

/*
算法思路:
a表逆置,b表逆置,整个链表逆置
时间复杂度:On 空间复杂度O1
*/

void Reverse_List(SLDateType* a, int sz)
{
	int begin = 0;
	int end = sz - 1;
	while (begin < end)
	{
		swap(a[begin], a[end]);
	}
}

void Dul_List_Swap_Position(SL& pl, int m, int n)
{
	Reverse_List(pl.a, m);
	Reverse_List(pl.a + m, n);
	Reverse_List(pl.a, m + n);

}

11. [2011统考真题]找两个顺序表合并的中位数

一个长度为L (L≥1) 的升序序列s,处在第[L/2]个位置的数称为s的中位数。例如,若序列S1=(11,13,15,17,19),则S的中位数是15, 两个序列的中位数是含它们所有元素的升序序列的中位数。例如,若S2=(2, 4, 6, 8, 20),则S;和S2的中位数是11.现在有两个等长升序序列A和B,试设计一个在时间和空间两方面都尽可能高效的算法,找出两个序列A和B的中位数。要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用C或C++或Java语言描述箕法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
using namespace std;

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	size_t size;
	size_t capacity;
}SL;

/*
算法思路:
类似两个链表合并成一个链表

时间复杂度:On 空间复杂度O1
*/

/*

int Find_Mid(SL& p1, SL& p2)
{
	int i = 0;
	int j = 0;
	int len = (p1.size + p2.size)/2;
	int x = 0;
	while (i < p1.size && j < p2.size)
	{
		if (p1.a[i] < p2.a[j])
		{
			i++;
			x = p1.a[i];
		}
		else
		{
			j++;
			x = p1.a[i];
		}

		if (i + j == len)
		{
			break;
		}
	}
	
	return x;
}

*/


/*
算法思路:
分别查找两个数组的中位数
a = b,则为中位数
a < b, 中位数在 a的数组右边,b的左边
a > b, 反之
最后分别剩1个数,较小为中位数
*/

int Find_Mid(SL& p1, SL& p2)
{
	int left1 = 0;
	int right1 = p1.size - 1;
	int mid1 = (left1 + right1) / 2;
	int left2 = 0;
	int right2 = p1.size - 1;
	int mid2 = (left2 + right2) / 2;
	

	while (left1 != right1 && left2 != right2)
	{

		if (p1.a[mid1] < p2.a[mid2])
		{
			//留下右边
			if (left1 < right1)
			{
				left1 = mid1 + 1;
				mid1 = (left1 + right1) / 2;
			}

			//留下左边
			if (left2 < right2)
			{
				right2 = mid2 - 1;
				mid2 = (left2 + right2) / 2;
			}
		}

		//反之
		if (p1.a[mid1] > p2.a[mid2])
		{
			//留下右边
			if (left2 < right2)
			{
				left2 = mid2 + 1;
				mid2= (left2 + right2) / 2;
			}

			//留下左边
			if (left1 < right1)
			{
				right1 = mid1 - 1;
				mid1 = (left1 + right1) / 2;
			}
		}

		
	}

	return p1.a[mid1] > p1.a[mid2] ? p1.a[mid1] : p2.a[mid2];
}

12. [2013统考真题]出现超过一半的元素

已知一个整数序列A = (a0, a1,an-1),其中0<a<n(0≤i<n)。

若存在ap1=ap2= … =apm=x且m> n/2 (0≤pk<n, 1≤k≤m),则称x为A的主元素。例如A=(0,5,5,3,5,7,5,5),则5为主元素;又如A=(0,5,5,3,5,1,5,7), 则A中没有主元素,元素。假设A中的n个元素保存在一个一维数组中,请设计一个尽可能高效的算法,找
出A的主元素。若存在主元素,则输出该元素;否则输出-1. 要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用C或C++或Java语言描述算法,关键之处给出注释.
3)说明你所设计算法的时间复杂度和空间复杂度。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
using namespace std;

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	size_t size;
	size_t capacity;
}SL;


/*
算法思路:
出现并计数,不出现--,直到0,重新计数,最终次数大于0是备选人
再进行遍历查看出现次数
空间复杂度O1,时间复杂度On
*/

int Main_Ele(SL& pl)
{
	int x = 0;
	int count = 0;

	for (size_t i = 0; i < pl.size; i++)
	{
		if (x != pl.a[i])
		{
			if (count == 0)
			{
				x = pl.a[i];
			}
			else
			{
				count--;
			}
		}
		else
		{
			count++;
		}
	}

	if (count > 0)
	{
		int count = 0;
		for (size_t i = 0; i < pl.size; i++)
		{
			if (x == pl.a[i])
			{
				count++;
			}
		}
	}

	if (count > pl.size / 2)
	{
		return x;
	}

	return -1;
}

13. [2018统考真题] 数组未出现最小正整数

给定一个含n (n≥1)个整数的数组,请设计一个在时间上尽可能高.
效的算法,找出数组中未出现的最小正整数。例如,数组{-5,3, 2,3}中未出现的最小正
整数是1;数组{1,2,3}中未 出现的最小正整数是4.要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用C或C++语言描述算法,关键之处给出注释。.
3)说明你所设计算法的时间复杂度和空间复杂度。

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
using namespace std;

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	size_t size;
	size_t capacity;
}SL;

/*
算法思路:遇到负数忽略,寻找最小正数,
时间复杂度On,空间复杂度O1
*/

int Min_Pos_Int(SL& pl)
{
	int x = INT_MAX;
	for (size_t i = 0; i < pl.size; i++)
	{
		if (pl.a[i] > 0)
		{
			if (pl.a[i] < x)
			{
				x = pl.a[i];
			}
		}
	}

	return x;
}

14. [2020统考真题]三元数组最小距离

定义三元组(a, b,c) (a、 b、c均为正数)的距离D=|a-b| + |b-c| +|c-a|

给定3个非空整数集合S1、S2和S3按升序分别存储在3个数组中。请设计一个尽可能高效的算法 ,计算并输出所有可能的三元组(a,b,c) (a∈S|, b∈S2, cESj) 中的最小距离

例如Si={-1,0,9}, S2={-25,-10, 10,11}, S3= {2, 9, 17,30, 41},则最小距离为2,相应的三元组为(9, 10, 9)。要求:
1)给出算法的基本设计思想。
2)根据设计思想,采用C语言或C++语言描述算法,关键之处给出注释。
3)说明你所设计算法的时间复杂度和空间复杂度。

在这里插入图片描述

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <algorithm>
using namespace std;

typedef int SLDateType;
typedef struct SeqList
{
	SLDateType* a;
	size_t size;
	size_t capacity;
}SL;

bool Min(int a , int b, int c)
{
	if (a <= b && a <= c)
	{
		return true;
	}

	return false;
}

int ThreeArray_Min_Distance(SL& s1, SL& s2, SL& s3)
{
	//距离
	int d = INT_MAX;
	//数组下标
	int i = 0, j = 0, k = 0; 

	while (i < s1.size && j < s2.size && k < s3.size)
	{
		int ret = abs(s1.a[i] - s2.a[j]) + abs(s1.a[i] - s3.a[k]) + abs(s2.a[j] - s3.a[k]);
		if (ret < d)
		{
			d = ret;
		}

		if (Min(s1.a[i], s2.a[j], s3.a[k]))
		{
			i++;
		}
		else if (Min(s2.a[j], s1.a[i], s3.a[k]))
		{
			j++;
		}
		else
		{
			k++;
		}
	}

	return d;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凛音Rinne

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值