线性表习题
- 王道课后题
- 顺序表
- 1.从顺序表中删除具有最小值的元素
- 2.将顺序表L所有元素逆置
- 3.删除顺序表中所有值为x的元素
- 4.从有序表中删除元素值在s与t之间的所有元素
- 5.从顺序表中删除元素值在s与t之间的所有元素
- 6.从有序表中删除所有值重复的元素
- 7.★将两个有序顺序表合并成一个新的有序顺序表
- 8.(难)一个数组A[m+n]中有两个顺序表,将两个顺序表位置互换
- 9.顺序表元素递增有序,用最少时间查找数值为x的元素
- 10.将R中序列循环左移p个位置
- 链表
- 1.删除不带头结点的单链表L中所有值为x的节点
- 2.单链表L(带头结点),删除所有值为x的节点,并释放其空间
- 3.单链表(带头节点)从尾到头反向输出每个节点
- 4.在单链表(带头结点)中删除一个最小值节点
- 5.将带头结点的单链表就地逆置(空间复杂度为O(1))
- 6.带头结点的单链表,使其元素递增有序
- 7.带头结点单链表无序,删除所有介于两个给定值s和t之间的元素
- 8.两个单链表,找到公共节点
- 9.按递增次序输出单链表中各节点的数据元素,并释放节点空间
- 10.带头结点单链表A,将其中奇数位置元素放在A,偶数在B
- 12.递增有序单链表,去掉数值相同元素
- 21.查找链表中倒数第K各节点
- 循环链表
- 18.两个循环链表h1和h2,将h2合并到h1中
- 19.带头结点循环单链表反复找到最小节点输出,并删除
- 22.判断一个链表是否有环
- 25.后半部分逆置插入前段部分
- 栈
- 1.判断输入输出序列是否为合法序列
- 2.判断链表中n个字符是否中心对称
- 3.两个栈共享空间
- 栈和队列应用
- 1.判断表达式中的括号是否匹配问题,‘\0’作为结束符
王道课后题
顺序表
1.从顺序表中删除具有最小值的元素
并由函数返回被删除元素,空出位置由最后一个元素填补,若顺序表为空,则显示错误信息并推出运行
//分析1.找到最小元素下标
// 2.返回该元素
// 3.将最后一个元素覆盖最小元素
// 4.将length-1
bool DeleteMinElem(SqList &L,ElemType &e){
if(L.length == 0)
return false;
int min = L.data[0];
int pos;
for(int i = 1;i < L.length;i++){
if(min > L.data[i]){
min = L.data[i];
pos = i; //跳出循环i就没了
}
}
L.data[pos] = L.data[L.length - 1];
length--;
return true;
}
2.将顺序表L所有元素逆置
要求算法的时间复杂度为O(1)
//分析:扫描前半部分元素,与后半部分元素互换,界限为L.length / 2
void Reverse(SqList &L){
ElemType temp;
for(int i = 0;i < L.length / 2;i++){
temp = L.data[i];
L.data[i] = L.data[L.length - 1 - i];//0~length-1,1~length-1-1,i~length-1-i
L.data[L.length - 1 - i] = temp;
}
}
3.删除顺序表中所有值为x的元素
要求时间复杂度为O(n),空间复杂度为O(1)
//分析:将不为x的元素前移
bool DeleteX(SqList &L,ElemType e){
int k = 0; //有一个x元素就滞后i一次
for(int i = 0;i < L.length;i++){
if(L.data[i] != x){
L.data[k] = L.data[i]; //删除元素时常用思想:前移
k++; //不是要删除的元素就k++,是就不加,与i形成错位
}
}
L.length = k;
}
4.从有序表中删除元素值在s与t之间的所有元素
要求s<t,若s或t不合理或顺序表为空时,显示错误
//分析:1.排除错误情况
// 2.分别找到位置为s和t的元素
// 3.将t的元素代替s的元素即删除
// 4.修改长度
bool DeleteSToT(SqList &L,ElemType s,ElemType t){
int num_s,num_t;
if(s >= t || L.length == 0) //排除错误情况
return false;
for(int i = 0;i < L.length;i++){ //找到s下标
if(L.data[i] == s){
num = i;
break;
}
}
if(i >= L.length)
return false;
for(int j = 0;j < L.length;j++){ //找到t下标
if(L.data[j] == t){
num = j;
break;
}
}
while(j < L.length){ //替换
L.data[i] = L.data[j];
i++;
j++;
}
L.length = i; //改长度
return true;
}
//王道答案
bool DeleteSToT(SqList &L,ElemType s,ElemType t){
int i,j; //定义在外面后面要用
if(s <= t || L.length == 0)
return false;
for(i = 0;i < L.length && L.data[i] < s;i++);
if(i >= L.length)
return false;
for(j = 0;j < L.length && L.data[j] < t;j++);
for(;j < L.length;i++,j++)
L.data[i] = L.data[j];
L.length = i;
return true;
}
5.从顺序表中删除元素值在s与t之间的所有元素
包含s和t,要求s<t,若s或t不合理或顺序表为空时,显示错误
//分析: 1.排除错误情况
// 2.遍历顺序表
// 3.若为要求元素则
bool DeleteSToT(SqList &L,ElemType s,ElemType t){
int i,k = 0; //k用于表示s与t之间元素个数
if(s >= t || L.length == 0)
return false;
for(i = 0;i < L.length;i++){
if(L.data[i] <= s && L.data[i] >= t){
L.data[k] = L.data[i] //删除元素时常用思想:前移
k++; //不是要删除的元素就k++,是就不加,与i形成错位
}
}
L.length = k
return true;
}
6.从有序表中删除所有值重复的元素
使表中所有元素均不同
//分析: 1.遍历表
// 2.设置两个变量j,seek(相当于指针)seek用来在后面不断寻找元素,j用来方便记录前移位置,顺便记录元素个数
// 3.seek变量找到与j变量不同的元素时前移,并j++;相同时j不变,seek继续往下寻找
bool DeleteSame(SqList &L){
int j = 1;
int seek = 1; //寻找下一个不相同的元素
if(L.length == 0)
return false;
for(;seek < L.length;seek++){
if(L.data[seek] != L.data[seek - 1]){ //这里j也可以是seek-1,都是相同的元素
L.data[j + 1] = L.data[seek]; //寻找指针找到不同元素时将元素前移
j++;
}
}
L.length = j;
}
7.★将两个有序顺序表合并成一个新的有序顺序表
并由函数返回结果顺序表
//分析: 1.排除错误情况:A+B元素长度小于等于C最大长度
// 2.不断取下A,B两个顺序表的表头元素,比较,较小的放入C
// 3.一个表全部比较完后,若A或B还有剩余,全部填至C中
bool Merge(SqList A,SqList B,SqList &C){
int a = 0,b = 0,c = 0;
if(A.length + B.length > C.MaxSize)
return false;
while(a < A.length && b < B.length){
if(A.data[a] <= B.data[b])
C.data[c++] = A.data[a++];
else
C.data[c++] = B.data[b++];
}
while(a < A.length)
C.data[c++] = A.data[a++];
while(b < B.length)
C.data[c++] = B.data[b++];
C.length = k;
return true;
}
8.(难)一个数组A[m+n]中有两个顺序表,将两个顺序表位置互换
bool Reverse(SqList &L,int left,int right){
int temp;
for(int i = left;i <=(left + right) / 2;i++){
temp = L.data[i];
L.data[i] = L.data[left + rigth - i];
L.data[left + right - i] = temp;
}
}
void Exchange(SqList &L,int m,int n){
Reserve(L,0,m + n - 1); //对整体
Reserve(L,0,n - 1); //对前n个
Reserve(L,n,m + n - 1); //对后m个
}
9.顺序表元素递增有序,用最少时间查找数值为x的元素
找到,与后继元素互换;找不到,插入表中并使表仍然有序
//分析:1.折半查找x元素
//2.找到与后一个元素互换
//3.找不到插入右指针下一个位置
void FindX(SqList &L,int x){
int left,right,mid;
left = 0,right = L.length - 1;
while(left <= right){
mid = (left + right) / 2;
if(L.data[mid] == x)
break;
else if(L.data[mid] < x)
left = mid + 1;
else if(L.data[mid] > x)
right = mid - 1;
}
if(L.data[mid] == x && mid != L.length - 1){ //找到x,且x不是最后一个元素(无法交换)
int temp = L.data[mid];
L.data[mid] = L.data[mid + 1];
L.data[mid + 1] = temp;
}
if(right < left){ //没找到
for(int i = L.length - 1;i > right;i--){
L.data[i + 1] = L.data[i];
}
L.data[right + 1] = x;
}
}
10.将R中序列循环左移p个位置
时间空间尽可能高
void Reverse(int R[],int left,int right){
for(int i = left;i <= (left + right) / 2;i++){ //从左边遍历到中间
int temp = R[i];
R[i] = R[left + right - i];
R[left + right -1] = temp;
}
}
void Exchange(int R[],int n,int p){
Reverse(R,0,n - 1);
Reverse(R,0,n - p - 1);
Reverse(R,n - p,n - 1);
}
链表
1.删除不带头结点的单链表L中所有值为x的节点
//分析:1.需要一个p指针指向要删除节点
//2.递归,是x元素,执行操作:p指向该节点,L指向下一个,释放p,继续递归L
//3.不是x元素,继续递归L->next
void DeleteXNode(LinkList &L,ElemType x){
LNode *p;
if(L->next == NULL)
return;
if(L->data == x){
p = L;
L = L->next;
free(p);
DeleteXNode(L,x);
}else
DeleteXNode(L->next,x);
}
2.单链表L(带头结点),删除所有值为x的节点,并释放其空间
值为x的节点不唯一
//分析:1.三个指针,分别:工作指针,前驱指针,释放节点指针
//2.若是x:q指针指向x,p后移,连接pre与p节点,free(q)
//3.不是x:p,pre后移
void DeleteXNode(LinkList &L,ElemType x){
LNode *p,*pre,*q; //分别:工作指针,前驱指针,释放节点指针
while(p != NULL){
if(p->data == x){
q = p;
p = p->next;
pre->next = p;
free(q);
}else{
pre = pre->next;
p = p->next;
}
}
}
3.单链表(带头节点)从尾到头反向输出每个节点
//分析:1.递归寻找下一个元素
//2.返回时依次打印输出
void ReversePrint(LinkList L){
if(L->next == NULL)
print(L->data);
else
ReversePrint(L->next);
}
4.在单链表(带头结点)中删除一个最小值节点
效率高,假设最小值节点唯一
//分析:1.指针:工作遍历指针,前驱指针,指向最小值节点指针;变量:最小值
void DeleteMinNode(LinkList &L){
LNode *p = L->next,*pre = L,*min = p,*minpre = pre;
ElemType value = p->data;
while(p != NULL){
if(p->data < min->data){
min = p;
minpre = pre;
}
p = p->next;
pre = pre->next;
}
minpre->next = min->next;
free(min);
}
5.将带头结点的单链表就地逆置(空间复杂度为O(1))
//分析:断开节点重新连结
//1.初始化:断开头节点,头节点指向NULL
//2.指针:工作指针p处理连结,r指针指向断开后段
//3.重新连结:从p断开,r指向p的下一个,使p指向L的下一个,使L指向p
void ReverseSpaceOne(LinkList &L){
LNode *p = L->next,r;
L->next = NULL;
while(p != NULL){
r = p->next;
p->next = L->next;
L->next = p;
p = r;
}
}
6.带头结点的单链表,使其元素递增有序
//分析:断开重新连结并排序
//1.初始化:断开头节点,头节点指向NULL
//2.指针:p工作指针处理连结,r指针指向断开后段,f前段排序指针
//3.重新连结并排序
void UpSort(LinkList L){
LNode *p = L->next,*r,*f = L;
L->next = NULL;
while(p != NULL){
r = p->next;
while(f->next->data < p->data && f->next != NULL)
f = f->next;
p->next = f->next;
f->next = p;
p = r;
}
}
7.带头结点单链表无序,删除所有介于两个给定值s和t之间的元素
//分析:指针:工作指针p,前驱指针pre
//判断p节点指向值是否要删除
//是删除元素:使r指向节点指向删除节点的下一个节点,释放p节点,再使p指向
//不是删除元素:p,r继续遍历
void DeleteStoT(LinkList &L,ElemType s,ElemType t){
LNode *p = L->next,*pre = L;
while(p != NULL){
if(p->data > s && p->data <t){
r->next = p->next;
free(p);
p = r->next;
}else{
r = p;
p = p->next;
}
}
}
8.两个单链表,找到公共节点
//分析:1.先将长的链表遍历到两链表一样长
//2.两链表开始对比:当前节点的值,若相同则找到;若不相同,继续遍历
//3.指针:long指针,short指针;变量:两链表长度,两链表长度差值
LNode *ShareNode(LinkList L1,LinkList L2){
LNode *L,*s;
int len1 = Length(L1),len2 = Length(L2),disp;
if(len1 < len2)
disp = len2 - len1;
L = L2->next;
S = L1->next;
if(len1 > len2)
disp = len1 - len2;
L = L1->next;
S = L2->next;
while(disp != 0)
L = L->next;
disp--;
while(l != NULL){
if(L->data == S->data)
return L;
else{
L = L->next;
S = S->next;
}
}
return NULL;
}
9.按递增次序输出单链表中各节点的数据元素,并释放节点空间
不使用数组作为辅助空间
//分析:每遍历一次输出一个最小元素
void PrintMin(LinkList &L){
LNode *p,*min;
while(L->next != NULL){
p = L->next;
min = p;
while(p->next != NULL){
if(p->next->data < min->data)
min = p;
p = p->next;
}
LNode *x = min->next
print(x->data);
min->next = x->next;
free(x);
}
free(L);
}
10.带头结点单链表A,将其中奇数位置元素放在A,偶数在B
//分析:指针:A表指针,B表指针,
//1.odd的下一个元素给x记录下来,odd元素next指向odd的下下个元素
//2.偶数位置元素给B,even指针后移,even指向元素next置为NULL;
LinkList Separate(LinkList &A){
LinkList B = (LinkList)malloc(sizeof(LNode));
B->next = NULL;
LNode *odd = A->next,*even = B,*x;
while(odd->next != NULL){
x = odd->next
odd->next = odd->next->next;
even->next = x->next;
even = even->next;
odd = odd->next;
}
even->next = NULL;
return B;
}
12.递增有序单链表,去掉数值相同元素
//分析:指针:工作指针p
void DeleteSame(LinkList &L){
LNode *p = L->next,*x;
while(p != NULL){
if(p->next->data == p->data){
x = p->next;
p->next = x->next;
free(x);
}else
p = p->next;
}
}
21.查找链表中倒数第K各节点
查找成功输出该节点值,并返回1,否则返回0
//分析:指针:前指针,后指针
//1.后指针先跑k个节点,然后两个指针一块跑,后面指针为空时,前面指针即为倒数第k个元素
//返回值,若count还<k:k超过线性表长度;count=k:查找成功
int SearchK(LinkList L,int k){
LNode *p = L,*q = L;
int count = 1;
while(p != NULL){
if(count < k)
count++
else
q = q->next;
p = p->next;
}
if(count < k)
return 0;
else{
printf("%d",q->data);
return 1;
}
}
循环链表
18.两个循环链表h1和h2,将h2合并到h1中
//分析:指针:寻找h1的表尾指针,寻找h2的表尾指针
//1.分别遍历寻找h1,h2的表尾
//2.拼接
LinkList Joint(LinkList &h1,LinkList &h2){
LNode *tail1 = h1,*tail2 = h2;
while(tail1->next != h1)
tail1 = tail1->next;
while(tail2->next != h2)
tail2 = tail2->next;
tail1->next = h2->next;
tail2->next = h1;
return h1;
}
19.带头结点循环单链表反复找到最小节点输出,并删除
链表为空时,删除表头节点
//分析:指针:工作指针p,前驱指针pre,最小节点指针min
//1.循环遍历,并标记最小节点
//2.修改指针,释放节点;最终释放表头
void DeleteAll(LinkList &L){
LNode *p ,*pre,*premin,*min;
while(L->next != L){
premin = L;
min = L->next;
pre = L;
p = L->next;
while(p != L){
if(p->data < min->data){
min = p;
premin = pre;
}
p = p->next;
pre = pre->next;
}
premin->next = min->next;
printf("%d",min->data);
free(min);
}
free(L);
}
22.判断一个链表是否有环
如果有环,找出环的入口点并返回;否则返回NULL
//分析:指针:快指针,慢指针
//1.快指针和慢指针再次相遇的时候,说明有环;为NULL说明没环
LNode *SearchEnter(LinkList L){
LNode *slow = L,*fast = L;
while(slow != NULL && fast != NULL){
slow = slow->next;
fast = fast->next->next;
if(slow == fast)
break;
}
if(slow == NULL && fast == NULL)
return NULL;
..........不会了
}
25.后半部分逆置插入前段部分
//分析:指针:
//1.先找到中间(需要逆置部分的头节点)
//2.就地逆置(断开重新连接)
//3.插入,断开的同时,进行插入操作
void ReverseAndInsert(LinkList &L){
LNode *p,*q,*r,*l;
while(p != NULL)
}
栈
1.判断输入输出序列是否为合法序列
//分析:
//1.遍历序列
//2.若是I就i+1,若是O就o+1
//3.特殊情况:入栈过程中入栈次数≥出栈次数,否则返回false
//4.要求栈为空:最终i = o,否则返回false
bool Judge(char A[]){
int k;
int i = 0,o = 0;
while(A[k] != '/0'){
switch(A[k]){
case 'I':
i++;
break;
case 'O':
o++;
if(o > i)
return fasle;
}
i++;
}
if(o != i)
return false;
else
return true;
}
2.判断链表中n个字符是否中心对称
//分析:
//1.将前半段链表元素进栈,
//2.然后栈每弹出一个元素,就与链表后半段元素比较,相同继续比较,不相同则返回false
//3.直到栈为空,特殊情况:n为奇数时,跳过中间那个,从下一个开始比较
bool Symmetry(LinkList L,int n){
int top = 0; //栈内元素个数
char A[n/2]; //栈
LNode *p = L->next;
for(int i = 0; i < n/2;i++){
A[i] = p->data;
p = p->next;
}
i--; //指向栈顶元素
if(n % 2 = 1)
p = p->next;
while(p != NULL && A[i] == p->data){
p = p->next;
i--;
}
if(i == -1)
return true;
else
return false;
}
3.两个栈共享空间
结构定义
#define MaxSize 100
#define ElemType int
typedef struct {
ElemType A[MaxSize];
int top
}
栈和队列应用
1.判断表达式中的括号是否匹配问题,‘\0’作为结束符
//分析:1.遇到左括号就入栈;2.遇到右括号,判断括号类型是否与栈顶括号对应
//2.遍历:只有不是括号时,i+1
bool BracketCheck(char str[]){
int i = 0,x;
SqStack S;
InitStack(S);
while(str[i] != '\0'){
if(str[i] == '(' || str[i] == '[' || str[i] == '{'){
Push(S,str[i]);
break;
}
switch(str[i]){
case ')':
Pop(S,x);
if(x != '(')
return false;
case ']':
Pop(S,x);
if(x != '[')
return false;
case '}':
Pop(S,x);
if(x != '{')
return false;
default:
break;
}
i++;
}
if(!EmptyStack(S))
return false;
return true;
}