//
// Created by Administrator on 2023/3/31.
//
#ifndef SHUJUJIEGOU_LIST_H
#define SHUJUJIEGOU_LIST_H
#endif //SHUJUJIEGOU_LIST_H
using namespace std;
/**
* 假设线性表第0位为空,现在用来放线性表长度
* 线性表基本操作:
* InitList(&L) 初始化表
* Length(L) 求表长
* LocateElem(L,e) 按值查找
* GetElem(L,i) 按位查找
* ListInsert(&L,i,e) 插入操作,在表的第i个位置插入元素e
* ListDelete(&L,i,&e) 删除操作,删除表上第i个位置的元素,返回给e
* PrintList(L) 输出操作
* Empty(L) 判空操作
* DestroyList(&L) 销毁操作
*/
void InitList(int L []);
void Length(int L []);
int LocateElem(const int L [] , int e);
int GetElem(int L[], int i);
void ListInsert(int L [] , int i , int e);
void ListDelete(int L [] , int i , int &e);
void PrintList(int L []);
int Empty(const int L []);
void DestroyList(int L []);
/*
* 已知一个整数序列A=(a_0,a_1,a_2,...,a_n-1),其中0≤a_i≤n(0≤i<n)。如果存在a_p1=a_p2=...=a_pm=x且m>n/2(0≤p_k<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中的元素保存在一个一维数组中,
* 请设计一个尽可能高效的算法,找出A的主元素。若存在主元素,则给出该元素;否则输出-1
*
*/
int GetMajority(const int L[]);
/*
* 定义三元组(a,b,c)(a,b,c均为正数)的距离D=|a-b|+|b-c|+|c-a|。给定3个非空整数集合S_1,S_2,S_3,按升序分别存储在3个数组中。请设计一个尽可
* 能高效的算法,计算并输出所有可能的三元组(a,b,c)(a∈S_1,b∈S_2,c∈S_3)中的最小距离。例如S_1=-1,0,9, S_2=-25,-10,10,11,
* S_3=2,9,17,30,41则最小距离为2,相应的三元组为(9,10,9)。
*/
int GetMinDistance(int S1[], int S2[], int S3[]);
//单链表,同时让头指针存链表长度
typedef struct LNode
int data;
struct LNode* next;
LNode,*LinkList;
//初始化链表
LinkList Init_LinkList();
//头插法建立单链表(函数内部就不去再调用cin或者是scanf了,太蠢了,增加一个列表形参,列表处理和上面的列表相同,数据下标从1开始,0位置存长度)
LinkList List_HeadInsert(LinkList &L , const int A []);
//尾插法建立单链表
LinkList List_TailInsert(LinkList &L , const int A []);
//按序号查找节点值
LNode* GetElem(LinkList L, int i);
//按值查找表节点
LNode* LocateElem(LinkList L, int e);
//插值操作:在第p个节点后插入
void LNode_InsertTail(int e, LNode* p);
//插入操作:在第p个节点前插入
void LNode_InsertHead(LinkList L, int e, LNode* p);
//删除节点操作
void Delete_LNode(LinkList L, LNode *p);
//求表长
int GetLength(LinkList L);
//有一个带头节点的单链表L,编写算法使其元素递增有序
//方法一:用类似快排的方式去写这个代码,有一个起始指针和一个终止指针,我们的id值是每个子链表的第一个节点,比当前节点小的节点我们删掉然后用头插法
//插进去,比当前节点大的节点我们直接忽略掉,进行下一个节点的判断,id节点最后会移动到一个位置,于是分出了两个子链表。但是毕竟是链表,不是很方便。
//方法二:插入排序
void Sort_LinkList(LinkList L);
//给定两个单链表,编写算法写出两个单链表的公共节点的起始位置
LNode* Both_Have(LinkList L1, LinkList L2);
//再不改变链表的前提下,设计一个尽可能高效的算法,查找链表中倒数第k个位置上的节点(k为正整数),若查找成功,算法输出该节点的data值,并返回1,否则只
//返回0
int Get_k_Tail(LinkList L, int k);
//现要求设计一个时间复杂度尽可能高效的算法,对于链表中data的绝对值相等的节点,仅保留第一次出现的节点而删除其余绝对值相等的节点。
void Delete_Same_abs(LinkList L);
//设有线性表L=(a_1,a_2,a_3,...a_n-2,a_n-1,a_n)采用带头节点的链表存储
// 设计一个空间复杂度为O(1)且时间上尽可能高的算法,重新排列L中的各节点,得到线性表L'=(a_1,a_n,a_2,a_n-1,...)
LinkList Resort(LinkList L);
//双链表
typedef struct DNode
int data ;
struct DNode * next;
struct DNode * pre;
DNode, *DLinkList;
//双链表的插入操作(默认为第p位置的后面)
void DNode_InsertTail(DLinkList DL, int e , DNode* p);
//双链表的删除操作
void DNode_Delete(DNode *p);
//循环链表
//静态链表
//以next==-1作为结束的标志
typedef struct
int data;
int next;
StaticLinkList[INT_MAX];
.cpp文件
//
// Created by Administrator on 2023/3/31.
//
#include <iostream>
#include "../Public/List.h"
using namespace std;
/**
* 假设线性表第0位为空,现在用来放线性表长度
* 线性表基本操作:
* InitList(&L) 初始化表
* Length(L) 求表长
* LocateElem(L,e) 按值查找
* GetElem(L,i) 按位查找
* ListInsert(&L,i,e) 插入操作,在表的第i个位置插入元素e
* ListDelete(&L,i,&e) 删除操作,删除表上第i个位置的元素,返回给e
* PrintList(L) 输出操作
* Empty(L) 判空操作
* DestroyList(&L) 销毁操作
*/
void InitList(int L [])
int *List = new int [20];
L = List;
for(int i = 0 ; i < 20 ; i++)
L[i] = -1; //初始化
void Length(int L [])
int i = 0;
int count = 0;
while(L[i]!=-1)
count++;
i++;
L[0] = count;
//此处用二分法优化,前提是线性表为一个有序列表
//返回-1表示没有找到
int LocateElem(const int L [] , int e)
int low = 1;
int high = L[0]-1;
int mid ;
while(low<high)
mid = (low+high)>>1;
if (L[mid]>e)
high = mid-1;
continue;
else if (L[mid]<e)
low = mid+1;
continue;
else
return mid;
return -1;
int GetElem(int L[], int i)
if (i>=L[0]) return -1;
else return L[i];
void ListInsert(int L [] , int i , int e)
// 判断是否越界
if (i>=L[0])
printf("OUT OF BOUNDARY!");
return;
else
// 在表长内,先挪位置
for (int j = L[0]; j >= i; --j)
L[j+1] = L[j];
L[i] = e;
cout<<L[i]<<endl;
L[0]++;
void ListDelete(int L [] , int i , int &e)
// 判断是否越界
if (i>L[0])
cout<<"OUT OF BOUNDARY"<<endl;
return;
e = L[i];
// 用覆盖的方式去删除
for (int j = i; j <= L[0] ; ++j)
L[j] = L[j+1];
L[0]--;
void PrintList(int L [])
for (int i = 1; i <= L[0]; ++i)
cout<<L[i]<<endl;
int Empty(const int L [])
if (L[0]==0)return 1;
else return 0;
void DestroyList(int L [])
free(L);
/*
* 已知一个整数序列A=(a_0,a_1,a_2,...,a_n-1),其中0≤a_i≤n(0≤i<n)。如果存在a_p1=a_p2=...=a_pm=x且m>n/2(0≤p_k<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中的元素保存在一个一维数组中,
* 请设计一个尽可能高效的算法,找出A的主元素。若存在主元素,则给出该元素;否则输出-1
*
*/
int GetMajority(const int L[])
//初始化
int id = L[1];
int count = 1;
// 找出个数最多的那个元素,前面的指定元素个数和后面的其它元素个数相互抵消,只要前面的指定元素够多,那么id所指的元素一定是前面的那个指定元素
// 如果前面的指定元素个数不够多,那么当指定元素的个数被抵消完后,会将下一个元素重设为指定元素,然后继续进行抵消,整个数组遍历下来会有几个情况:
// 1.count结果=0,意味着所有指定元素的个数(赋值给id的元素)等于未指定的所有元素的个数之和(没有给id赋值的),那么指定过的元素也肯定不是主元素
// 2.count结果>0,意味着这个count所指向的元素就是这个数组内出现次数最多的,但是还需要确定该元素出现的次数是否大于数组长度的一半
// 寻找出现次数最多的元素
for (int i = 2; i <= L[0]; ++i)
if (id == L[i])
count++;
else
if (count>0)
count--;
else
count = 1;
id = L[i];
// 确定指定元素的出现次数是否大于数组长度的一半
if (count>0)
count = 0;
for (int i = 1; i <= L[0]; ++i)
if (id==L[i])
count++;
if (count>L[0]/2) return id;
else return -1;
return -1;
/*
* 定义三元组(a,b,c)(a,b,c均为正数)的距离D=|a-b|+|b-c|+|c-a|。给定3个非空整数集合S_1,S_2,S_3,按升序分别存储在3个数组中。请设计一个尽可
* 能高效的算法,计算并输出所有可能的三元组(a,b,c)(a∈S_1,b∈S_2,c∈S_3)中的最小距离。例如S_1=-1,0,9, S_2=-25,-10,10,11,
* S_3=2,9,17,30,41则最小距离为2,相应的三元组为(9,10,9)。
*/
bool xls_min (int a , int b , int c)
if (a<=b&&a<=c) return true;
return false ;
int GetMinDistance(int S1[], int S2[], int S3[])
// 做个假设,对于三个数组和三元组内的三个值来说,顺序都无所谓,所以可以假设a<b<c这样方便做题
// 距离D可以转化为2(|a-b|+|b-c|)或者是2|a-c|但是第二个等式成立有个前提那就是存在b∈一个数组,使得a<b<c也就是说这个b一定是中间值
// 定义一个D值为最大值,确保D一定会被重新赋值
// 题给三个数组都是递增数组,那么我们直接从数组的第一个元素开始计算D值,每次取最小的那个值进行放大,然后重新算D求最小值,相当于一次所有表的遍历
int i=1,j=1,k=1;//三个数组的指针
int D_min = INT_MAX;
// 指针走到头之前
while(i<=S1[0]&&j<=S2[0]&&k<=S3[0]&&D_min>0)
int D = abs(S1[i]-S2[j])+ abs(S1[i]-S3[k])+ abs(S2[j]-S3[k]);
if (D<D_min)
D_min = D;
if (xls_min(S1[i], S2[j], S3[k]))i++;
else if (xls_min(S2[j], S1[i], S3[k])) j++;
else k++;
return D_min;
LinkList Init_LinkList()
auto *L = new LNode;
L->next = nullptr;
L->data = 0;
return L;
LinkList List_HeadInsert(LinkList &L , const int A [])
for (int i = 1; i <= A[0]; ++i)
auto * p = new LNode ;
p->data = A[i];
p->next = L->next;
L->next = p;
L->data++;
return L;
LinkList List_TailInsert(LinkList &L , const int A [])
//定义一个指向链表尾部的指针
LNode* Tail = L;
for (int i = 1; i <= A[0] ; ++i)
auto *p = new LNode;
p->data = A[i];
Tail->next = p;
p->next = nullptr;
Tail = p;
L->data++;
return L;
LNode* GetElem(LinkList L, int i)
if (i>L->data)return nullptr;
//计数,直到找到第i个节点为止
int index = 0;
LNode *p = L;
while (index!=i)
p = p->next;
index++;
return p;
LNode* LocateElem(LinkList L, int e)
int index = 0;
LNode *p = L;
while(index<=L->data||p->next)//二选一
p = p->next;
index++;
if (p->data == e)return p;
return nullptr;
void LNode_InsertTail(int e, LNode* p)
auto * a = new LNode ;
a->data = e;
a->next = p->next;
p->next = a;
void LNode_InsertHead(LinkList L, int e, LNode* p)
auto* index = new LNode ;
index->next = L->next;
while (index->next&&index->next!=p)
index = index->next;
if (index->next)
auto *a = new LNode ;
a->data = e;
a->next = index->next;
index->next = a;
void Delete_LNode(LinkList L, LNode *p)
auto *index = new LNode ;
index->next = L->next;
while (index->next&&index->next!=p)
index = index->next;
index->next = p->next;
free(p);
int GetLength(LinkList L)
return L->data;
void DNode_InsertTail(int e , DNode* p)
auto *a = new DNode;
a->data = e;
a->next = p->next;
a->pre = p;
p->next->pre = a;
p->next = a;
void DNode_Delete(DNode *p)
p->pre->next = p->next;
p->next->pre = p->pre;
free(p);
//插入排序
//一共需要3个指针,两个拿来指向原来的链表,一个用来指向新的链表
void Sort_LinkList(LinkList L)
LinkList res = Init_LinkList();
auto *p = L->next;
auto *temp = p->next;
auto *new_p = res;
while (p)
new_p = res;
while (new_p->next&&new_p->next->data<p->data)
new_p = new_p->next;
LNode_InsertTail(p->data, new_p);
free(p);
p = temp;
temp = p->next;
L->next = res->next;
free(res);
LNode* Both_Have(LinkList L1, LinkList L2)
int len;
bool flag;
if (L1->data>L2->data)
len = L1->data-L2->data;
flag = true;
else
len = L2->data-L1->data;
flag = false;
auto *p1 = L1 ;
auto *p2 = L2 ;
int i = 0 ;
if (flag)
while (i<len)
p1 = p1->next;
i++;
else
while (i<len)
p2 = p2->next;
i++;
while(p1->next&&p2->next&&p1->next!=p2->next)
p1 = p1->next;
p2 = p2->next;
if (p1->next)return p1->next;
else return nullptr;
//时间复杂度为2n,也就是O(n)
int Get_k_Tail(LinkList L, int k)
//先遍历一遍查长度
int len = 0;
auto *p = L;
while (p->next)
len++;
p = p->next;
//如果len<k,那么直接输出0
if (len<k)return 0;
auto *r = L;
p = L;
int i = 0;
while (i<len)
p = p->next;
i++;
while (p->next)
p = p->next;
r = r->next;
cout<<r->data<<endl;
return 1;
void Delete_Same_abs(LinkList L)
auto *p = L->next ;
auto *r = L;
bool *flag =new bool [INT_MAX];
while (p)
if (flag[p->data])
flag[p->data] = true;
r = p;
p = p->next;
else
r->next = p->next;
free(p);
p = r->next;
LinkList Resort(LinkList L)
auto* p = L->next;
auto* q = L;
auto* new_L = Init_LinkList() ;
auto*r = new LNode ;
int len = 0;
//先看长为多少
while (p)
len++;
p = p->next;
//让新的头节点指向中间的那个节点,同时断开,变成两个子链表
for (int i = 0; i < len/2+len%2; ++i)
q = q->next;
r = q->next;
//用头插法进行倒序
while(q)
new_L->next = q;
q->next = new_L->next;
q = r;
r = q->next;
//进行插入操作
p = L->next;
q = new_L->next;
r = q->next;
//当两个链表不为空的时候,进行插值操作
while (p&&q)
q->next = p->next;
p->next = q;
p = q->next;
q = r;
r = q->next;
return L;