//
// Created by Yue on 2023-08-31.
//
#ifndef INC_2_2_1_SQLLIST_H
#define INC_2_2_1_SQLLIST_H
#define MaxSize 50
typedef int ElemType;
typedef struct {
ElemType data[MaxSize];
int length;
}SqlList;
// 插入一个新元素e, i 为位序
bool ListInsert(SqlList &L,int i, ElemType e)
{
if(i < 1 || i>L.length+1){
return false;
}
if (L.length >= MaxSize){
return false;
}
// 依次往后移动元素
for(int j=L.length;j>=i;j--){
L.data[j] = L.data[j-1];
}
L.data[i-1] = e;
L.length++;
return true;
}
// 删除操作,给定位序i,删除对应位序i上的元素,并用e将值带回来
bool ListDelete(SqlList &L,int i,ElemType &e){
if (i <= 1 || i >L.length)
return false;
e = L.data[i-1];
for (int j=i-1;j<L.length-1;j++){
L.data[j] = L.data[j+1];
}
L.length--;
return true;
}
// 按值查找
int LocateElem(SqlList L,ElemType e){
for(int i=0;i<L.length;i++){
if(L.data[i] == e){
return i+1;
}
}
return 0;
}
// 按位查找
ElemType GetElem(SqlList L,int i){
return L.data[i-1];
}
// 2.2.3 第1题 删除最小值的元素,并由函数返回被删除的值。空出的位置由最后一个元素填补
bool DeleteMin(SqlList &L,ElemType &value){
if (L.length <= 0)
return false;
ElemType min=L.data[0];
int minIndex=0;
for(int i=1;i<L.length;i++){
if (L.data[i] < min){
min = L.data[i];
minIndex = i;
}
}
L.data[minIndex] = L.data[L.length-1];
L.length--;
value = min;
return true;
}
// 第2题设置一个高效的算法,将顺序表L的所有元素逆置,要求空间复杂度为O(1)
void ListReverse(SqlList &L){
for(int i=0;i<L.length/2;i++){
ElemType temp = L.data[i];
L.data[i] = L.data[L.length-1-i];
L.data[L.length-1-i] = temp;
}
}
// 第3题 删除线性表中所有值为x的元素,要求时间复杂度为O(n)
void ListDeleteElemX(SqlList &L,ElemType x){
// 思路:扫描一遍有多少个x
int count=0;
for (int i =0;i<L.length;i++){
if (L.data[i] == x){
count++;
}else{
L.data[i-count] = L.data[i];
}
}
L.length = L.length - count;
}
//第4题 从有序顺序表中删除其值在 s 与 t之间的所有元素
bool DeleteFromOrderedBetweenST(SqlList &L,ElemType s,ElemType t){
if(L.length == 0 || s>=t)
return false;
int firstS=-1;
int firstT=-1;
for (int i = 0;i<L.length;i++) {
if (L.data[i] >= s) {
firstS = i;
break;
}
}
for(int j=firstS;j<L.length;j++){
if(L.data[j] > t){
firstT = j;
break;
}
}
if(firstS >= L.length)
return false;
int k = 0;
for(int j = firstT;j<L.length;j++){
L.data[firstS+k]= L.data[j];
k++;
}
L.length = firstS+k; // 之前写的firstT-firstS+1想想什么问题
return true;
}
// 第4题 王道书中给出的代码
bool DeleteFromOrderedBetweenST(ElemType s,ElemType t,SqlList &L) {
// 删除有序顺序表L在给定值s与t之间的所有元素
if(s >= t || L.length == 0)
return false;
int i,j;
for(i=0; i<L.length && L.data[i] < s;i++); // 找的是第一个要删除的
if(i >= L.length)
return false;
for(j=i;j<L.length && L.data[j] <= t;j++); //找的是第一个不删除的
for (;j<L.length;j++,i++)
L.data[i] = L.data[j];
L.length = i;
}
// 第5题 从顺序表中删除其值在给定值s 与 t之间(包含s和t,要求s<t)的所有元素
bool DeleteBetweenST(SqlList &L,ElemType s,ElemType t){
if (L.length == 0 || s >= t)
return false;
// 沿用上一问的思路
// 或者记录不处于这个区间的个数
int count = 0;
for (int i = 0;i<L.length;i++){
if (L.data[i] < s || L.data[i] >t){
count ++;
L.data[count-1] = L.data[i];
}
}
L.length = count;
}
// 第6题 从有序表中删除其值重复的元素,使表中所有元素的值均不同
bool DeleteRepeatValue(SqlList &L){
if(L.length == 0)
return false;
if(L.length == 1)
return true;
int i,j;
int count=1;
for(i=1;i<L.length;i++){
if(L.data[i-1] != L.data[i]){
count++;
L.data[count-1] = L.data[i];
}
}
L.length = count;
return true;
}
// 王道书中的代码,虽然不太懂,但是妙啊
bool DeleteSame(SqlList &L){
if(L.length == 0)
return false;
int i,j; // i存储第一个不相同的元素,j为工作指针
for(i=0,j=1;j<L.length;j++){
if(L.data[i] != L.data[j]) // 查找下一个与上一个元素值不同的元素
L.data[++i] = L.data[j]; // 找到后将元素前移 // 相当于i保存了处理过的,在i之前的都是不重复的
}
L.length = i+1;
return true;
}
// 第7题 两个有序顺序表合并成一个新的有序顺序表
bool MergeTwoSorted(SqlList M,SqlList N,SqlList &C){
if (M.length + N.length > MaxSize){
return false;
}
// 思想: 按顺序比较两个有序表中的元素,每次将较小的元素放入新的有序表里
int i=0,j=0;
int k=0;
while(i<M.length && j <N.length){
if (M.data[i] <= N.data[j]){
C.data[k++] = M.data[i];
i++;
}else{
C.data[k++] = N.data[j];
j++;
}
}
while(i<M.length){
C.data[k++] = M.data[i++];
}
while(j<N.length){
C.data[k++] = N.data[j++];
}
C.length = k;
return true;
}
bool Merge(SqlList A,SqlList B,SqlList &C){
if(A.length + B.length > MaxSize)
return false;
int i=0,j=0,k=0;
while(i<A.length && j<B.length){
if(A.data[i] <= B.data[j])
C.data[k++] = A.data[i++];
else
C.data[k++] = B.data[j++];
}
while(i < A.length)
C.data[k++] = A.data[i++];
while(j < B.length)
C.data[k++] = B.data[j++];
C.length = k+1;
return true;
}
// 第8题 已知在一维数组A[m+n]中依次存放两个线性表。编写一个函数将两个线性表的位置互换
// 先逆置所有的,再逆置前n个,再单独逆置后m个
void ReverseArrayA(ElemType A[],int m,int n){
int i=0,j=m;
for(int i=0;i<(m+n)/2;i++){
ElemType temp = A[i];
A[i] = A[m+n-1-i];
A[m+n-1-i] = temp;
}
// 再逆置前n个
for(int i=0;i<n/2;i++){
ElemType temp = A[i];
A[i] = A[n-1-i];
A[n-1-i] = temp;
}
// 逆置后m个
for(int i=n;i<=(2*n+m-1)/2;i++){
ElemType temp = A[i];
A[i] = A[2*n+m-1-i];
A[2*n+m-1-i] = temp;
}
}
typedef int DataType;
void Reverse(DataType A[],int left,int right,int arraysize){
// 逆转
if (left >= right || right >= arraysize)
return;
int mid = (left+right)/2;
for(int i=0; i<= mid-left;i++){
DataType temp = A[left+i];
A[left+i] = A[right-i];
A[right-i] = temp;
}
}
void Exchange(DataType A[],int m,int n,int arraysize){
Reverse(A,0,m+n-1,arraysize);
Reverse(A,0,n-1,arraysize);
Reverse(A,n,m+n-1,arraysize);
}
// 第9题 线性表递增有序,最少时间在表中查找值为x的元素。若找到,将其与后继元素位置相交换,若找不到,则将其插入表中并使表中元素仍然有序
void SearchAndInsert(SqlList &L,ElemType x){
// 首先使用二分查找
int low = 0,high = L.length-1,mid;
while(low <= high){
mid = (low+high) / 2;
if(L.data[mid] == x) break;
else if(L.data[mid] > x) high = mid -1;
else if(L.data[mid] < x) low = mid +1;
}
if(low > high){
// 未找到该元素,此时low一定指向第一个大于x的位置
for(int i=L.length;i>low;i--){
L.data[i] = L.data[i-1];
}
L.data[low] = x;
L.length ++;
}
else if (mid != L.length-1){ // x不是最后一个元素,交换位置
int temp = L.data[L.length-1];
L.data[L.length-1] = x;
L.data[mid] = temp;
}
}
// 第10题 将数组循环左移p位
// 自己做不出来,看答案
void CircleMoveP(int p,int A[],int n){
// 可以将问题视为将数组ab, 转换成数组ba
// a 代表数组前p个元素,b 代表数组余下的n-p个元素
// 首先将整个数组逆置,再分别对前n-p个元素 、后p个元素进行逆置
// 即可得到数组ba
int i=0;
for(int i=0;i<n/2;i++){
ElemType temp = A[i];
A[i] = A[n-1-i];
A[n-1-i] = temp;
}
// 再逆置前n-p个
for(int i=0;i<(n-p)/2;i++){
ElemType temp = A[i];
A[i] = A[n-p-1-i];
A[n-p-1-i] = temp;
}
// 逆置后p个
for(int i=n-p;i<(2*n-p)/2;i++){
ElemType temp = A[i];
A[i] = A[2*n-p-1-i];
A[2*n-p-1-i] = temp;
}
}
// 第11题 求两个等长s升序序列的中位数
ElemType MediumOfTwoLinearList(SqlList M,SqlList N){
if(M.length != N.length || M.length == 0)
return -1;
// 我的思路:按照归并思路的方式,当取到第中间位置的元素时就返回
int i=0,j=0,count=0;
int temp = 0;
while(i<M.length && j<N.length){
if (M.data[i] <= N.data[j]){
temp = M.data[i];
i++;
}else{
temp = N.data[j];
j++;
}
count++;
if (count == M.length){
return temp;
}
}
}
// 王道书中的算法不理解
// 第12题 找主元素
// 思路: 第一遍扫描两两抵消掉不同的元素,最后留下的元素可能是主元
// 再第二遍扫描,计算是否大于n/2
bool FindPivotElement(int A[],int n,int &p){
if (n == 1)
return A[0];
int pivot = A[0],i=1;
int count = 1;
for(;i<n;i++){
if(A[i] == pivot){
count++;
}else{
count--;
if (count == 0){
pivot = A[i];
count = 1;
}
}
}
count = 0;
// 再一遍扫描计算pivot的个数
for(int i=0;i<n;i++){
if(pivot == A[i]){
count++;
}
}
if(count > n/2){
p = pivot;
return true;
}else{
return false;
}
}
// 暴力做法
bool FindPivotElement(int A[],int &p,int n){
int *arr = (int *) malloc(sizeof (int)*n);
for (int i=0;i<n;i++){
int temp = A[i];
int count = 0;
for(int j=0;j<n;j++){
if(A[j] == temp){
count++;
}
}
if(count > n/2){
p = temp;
return true;
}
}
return false;
}
// 第13题 寻找最小未出现的正整数
// 在时间上尽可能高效————以空间换时间
int FindMinDisappear(int A[],int n){
int *temparr = (int *) malloc(sizeof (int )*n);
for(int i=0;i<n;i++)
temparr[i] = 0;
for(int i=0;i<n;i++){
if(A[i]>0 && A[i] <= n)
temparr[A[i]-1] = 1;
}
for(int i=0;i<n;i++){
if(temparr[i] == 0){
return i+1;
}
}
return n+1;
}
// 暴力做法 时间复杂度 O(n^2) 空间复杂度O(1)
bool FindDisappearMinInt(int A[],int n,int &e){
int temp = 1;
while(true){
bool appear = false;
for(int i=0;i<n;i++){
if(A[i] == temp){
appear = true;
break;
}
}
if(appear == false){
e = temp;
return true;
}else{
temp++;
}
}
}
// 第14题 输出所有可能三元组中的最小距离
// 注意给的条件中S1,S2,S3都是升序的
// D = 2*{max(a,b,c) - min(a,b,c)}
// 改变min(a,b,c) 是一个最优策略,因为往后遍历a b c 都只会往D增大的方向改变
#define INT_MAX 0x7fffffff
// 找到三个数中最小数的下标 如果最小的是a 返回1,最小的是b返回2...
int MinOfThreeNums(int a,int b,int c){
if(a <= b && a <= c){ // 注意这里带 等号! 否则死循环!!!
return 1;
}else if(b <= a && b <= c){
return 2;
}else{
return 3;
}
}
int MinDistanceOfTriTuple(int S1[],int m,int S2[],int n,int S3[],int p){
int i=0,j=0,k=0;
int D_min = INT_MAX;
int D;
while(i<m && j<n && k<p){
D = abs(S1[i]-S2[j])+ abs(S1[i]-S3[k]) + abs(S2[j]-S3[k]);
if(D < D_min){
D_min = D;
// 找到此时三个数中最小的数的下标,将最小的数的下标右移
int min_index = MinOfThreeNums(S1[i],S2[j],S3[k]);
if(min_index == 1) i++;
else if(min_index == 2) j++;
else k++;
}
}
return D_min;
}
// 打印顺序表
void ListPrint(SqlList L){
cout<<L.length<<endl;
for (int i = 0;i < L.length;i++)
cout<<L.data[i]<<" ";
cout<<endl;
}
#endif //INC_2_2_1_SQLLIST_H
2024王道数据结构 大题01-线性表的顺序存储
最新推荐文章于 2024-09-04 11:16:25 发布