第二章 线性表
设计算法,逆置顺序表中所有元素
void Reverse(Sqlist &L)
{
int i, j;
int temp;
for (int i = 0, j = L.Length; i < j; i++, j++)
{
temp = L.data[i];
L.data[i] = L.data[j];
L.data[j] = temp;
}
}
设计算法,顺序表L中删除下标i~j的所有元素
void Del_span(Sqlist &L, int i, int j)
{
int dalta = j - i + 1; //元素移动的距离
for (int k = j + 1; k < L.length; k++)
{
L.data[k - dalta] = L.data[k];
}
L.length = dalta; // 修改表的长度
}
将顺序表L中所有小于表头元素的整数放在前半部分,大于表头元素的整数放在后半部分
注意:这个过程里面的i和j是轮流移动的,即j扫描结束换到i
void Put_x(Sqlist &L)
{
int temp;
int i = 0, j = L.length - 1;
temp = L.data[i];
while (i < j)
{
while (i < j && L.data[j] > temp)
j--;
if (i < j)
{
L.data[i] = L.data[j];
i++;
}
while (i < j && L.data[i] < temp)
i++;
if (i < j)
{
L.data[j] = L.data[i];
j--;
}
}
L.data[i] = temp;
}
有一个递增非空单链表,设计一个算法删除值域重复的结点
void Del_re(LNode *L)
{
LNode *p = L->next, *q;
while (p->next != NULL)
{
if (p->data == p->next->data)
{
q = p->next;
p->next = q->next;
free(q);
}
else
p = p->next;
}
}
删除单链表L(有头结点)中的一个最小值结点 (不太懂)
void Del_min(LNode *L)
{
LNode *pre = L, *p = pre->next, *minp = p, *minpre = pre;
while (p != NULL) // 查找最小值结点minp以及期前区结点minpre
{
if (p->dara < minp->data)
{
minp = p;
minpre = pre;
}
pre = p;
p = p->next;
}
minpre->next = minp->next; //删除*minp结点
free(minp);
}
线性表,带头结点的单链表L。设计算法将其逆置,要求不能建立新节点,只能通过表中已有节点的重新组合来完成。
void Reverse_1(LNode *L)
{
LNode *p = L->next, *q;
L->next = NULL;
while (p != NULL)
{
q = p->next; // q结点作为辅助结点来记录p的直接后继结点的位置
p->next = L->next; //将p所指的结点插入新的链表中,我觉得这里p->next = NULL应该也是对的
L->next = p; // 因为后继结点已经存入q中,所以p仍然可以找到后继
p = q;
}
}
将一个头结点为A的单链表分解成两个单链表A和B,使得A链表只含有原来链表中data域为奇数的结点,B链表为偶结点,且保持原来的相对顺序
void Depart_AB(LNode *A, LNode *&B)
{
LNode *p, *q, *r;
B = (LNode *)malloc(sizeof(LNode)); //申请链表B的头结点
B->next = NULL; //申请结点后的常规操作
r = B;
p = A;
while (p->next != NULL)
{
if (p->next->data % 2 == 0) // 挑出是偶数的,从链表中取下
{
q = p->next;
p->next = q->next;
q->next = NULL;
r->next = q; // 将取下的结点插入到r中
r = q;
}
else
p = p->next;
}
}
在N个个位正整数存放在int型数组A[0, … , N-1]中,N为已定义的常量且N≤9,数组N[]的长度为N,另给一个int型变量i,要求只用上述变量(A[0] ~A[N-1]与i,这N+1个整形变量)写一个算法,找出这N个整数中的最小者,并且要求不能破坏数组A[]中的数据。
void findMin(int a[], int &i) // i用来保存最小值
{
i = A[0]; // i先保存存入A[0]的值
while (i / 10 <= N - 1) // 取i的十位上的数字作为循环变量,与N-1作比较
{
if (i % 10 > A[i / 10]) // 取i的个位上的数字与A[i/10]中的各数值作比较
{
i = i - i % 10; // 如果i的个位上的数字大于A[i/10]中的数字,则将i的个位上的数字换成A[i/10]
i = i + a[i / 10];
}
i = i + 10; // i的十位上的数字加一,就是对A[]中的下一个数字进行检测
}
i = i % 10; // 循环结束后,i的个位上的数字保存了A[]中的最小值,将i更新为i的个位上的数字
}
逆序打印单链表中的数据局,假设指针指向了单链表的开始结点
void reprint(LNode *L)
{
if(L != NULL)
{
reprint(L->next);
cout << L->data << " ";
}
}
设有两个有序链表表示的集合A和B,判断他们是否相等
void isEqual(LNode *A, LNode *B)
{
LNode *p = A->next;
LNode *q = B->next;
while (p != NULL && q != NULL)
{
if(p->data == q->data)
{
p = p->next;
q = q->next;
}
else
return 0;
}
if(p != NULL || q != NULL) // 判断A、B两个序列长度是否相等
return 0;
else
return 1;
}
键盘输入n个英文字幕,请编程用输入数据建立一个单链表,并要求将字母不重复存入链表
void createLinkSameElem(LNode *head)
{
head = (LNode*)malloc(sizeof(LNode));
head->next = NULL;
LNode *p;
int n;
char ch;
scanf("%d", n);
for (int i = 0; i < n; i++)
{
scanf("%s", ch);
p = head->next;
while (p != NULL)
{
if(p->data == ch)
break;
p = p->next;
}
if(p == NULL)
{
p = (LNode*)malloc(sizeof(LNode));
p->data = ch;
p->next = head->next;
head->next = p;
}
}
}
第三章 栈和队列
假设以带头结点的循环链表表示队列,并且只设一个指针指向对为节点,但不设头指针,请写出相应的入队和出队算法。
// 入队
void enQueue(LNode *&rear, int x)
{
LNode *s = (LNode*)malloc(sizeof(LNode)); // 申请结点空间
s->data = x;
s->next = rear->next; //将s结点插入队尾
rear->next = s;
rear = s; //rear指向新队尾
}
// 出队
int deQueue(LNode *&rear, int &x)
{
LNode *s;
if(rear->next == rear)
return 0;
else
{
s = rear->next->next; // s指向开始结点
rear->next->next = s->next; // 队头元素出队
x = s->data;
if(s == rear) // 如果元素出队后队列为空
rear = rear->next; // 将rear指向头结点
free(s); // 释放队结点空间
return 1;
}
}
如果允许在循环队列地两端都可以进行插入和删除操作,要求:写出循环队列的类型定义;分别写出从队尾删除和从队头插入的算法。
// 结构体定义
typedef struct
{
int data[maxSize];
int front, rear;
}cysqueue;
// 出队算法(队尾删除)
int deQueue(cycqueue &Q, int &x)
{
if(Q.front == Q.rear) // 判断队是否为空
return 0;
else
{
x = Q.data[Q.rear];
Q.rear = (Q.rear - 1 + maxSize) % maxSize; // 修改队尾指针
return 1;
}
}
// 入队算法(队头插入)
int enQueue(cycqueue &Q, int x)
{
if(Q.rear == (Q.front - 1 + maxSize) % maxSize) // 判断队是否为满
return 0;
else
{
Q.data[Q.front] = x;
Q.front = (Q.front - 1 + maxSize) % maxSize; // 修改队头指针
return 1;
}
}
将一个非负的十进制整数N转换为一个二进制数
int BaseTrans(int N)
{
int i, result = 0;
int stack[maxSize], top = -1;
while (N != 0)
{
i = N % 2;
N = N / 2;
stack[++top] = i;
}
while (top != -1)
{
i = stack[top];
--top;
result = result*10 + i;
}
return result;
}
int bracketCheck(char f[])
{
stack S; char ch; // 定义一个栈
char* p = f;
while (*p != '\0') // 顺序扫描串中的每一个字符
{
if(*p == 39)
{
++p; // 跳过第一个单引号
while (*p != 39)
++p;
++p; // 跳过最后一个单引号
}
else if(*p == 34) // 双引号内的字符不参与配对比较
{
++p;
while (*p != 34) // 跳过第一个双引号
++p;
++p; // 跳过最后一个双引号
}
else
{
switch (*p)
{
case '{':
case '[':
case '(': push(A, *p);
// 出现左括号,进栈
break;
case '}': getTop(S, ch);
if(ch == '{')
pop(S, ch); // 栈顶的左花括号出栈
else
return 0;
break;
case ']': getTop(S, ch);
if(ch == '[') // 栈顶的左方括号出栈
pop(S, ch);
else
return 0;
break;
case ')': getTop(S, ch);
if(ch == '(') // 栈顶的左圆括号出栈
pop(S, ch);
else
return 0;
}
++p;
}
}
if(isEmpty(S))
return 1;
else
return 0;
}
设计一个递归算法,求n个不同字符的所有全排序列
void perm(char str[], int k, int n)
{
int i, j;
char temp;
if(k==0)
{
for (j = 0; j <= n-1; ++j)
printf("%c", str[j]);
}
else
{
for (i = 0; i <= k; ++i)
{
temp = str[k];
str[k] = str[i];
str[i] = temp;
perm(str, k-1, n);
temp = str[i];
str[i] = str[k];
str[k] = temp;
}
}
}
第四章 串
将串str中所有值为ch1的字符转换成ch2的字符,如果str为空串,或者串中不含值为ch1的字符,则什么都不做。
void replace(Str &str, char ch1, char ch2)
{
for (int i = 0; i < str.Length; i++)
{
if (str.ch[i] == ch1)
str.ch[i] = ch2;
}
}
实现串str的逆转函数,如果str为空串,则什么都不做
void swap(char& ch1, char& ch2)
{
char temp = ch1;
ch1 = ch2;
ch2 = temp;
}
void reverse(Str& str)
{
int i = 0;
int j = str.Length - 1;
while (i < j)
{
swap(str.ch[i], str.ch[j]);
++i;
--j;
}
}
删除str中值为ch的所有字符,如果str为空串或者串中不含值为ch的字符,则什么都不做
typedef stuct
{
char ch[maxSize];
int length;
}Str;
void delCh(Str &str, char ch)
{
if (str.length != 0)
{
for (int i = 0; i < str.length;)
{
if (str.ch[i] == ch)
{
for (int j = i; j < str.length - 1; ++j)
str.ch[j] = str.ch[j + 1];
--str.length;
}
else
++i;
}
str.ch[str.length] = '\0';
}
}
从串str中的pos位置起,求出与substr串匹配的子串的位置,如果str为空串,或者串中不含与substr匹配的子串,则返回-1做标记
int KMP(Str str, Str substr, int pos)
{
int i = pos, j = 1;
while (i <= str.length && j <= substr.length)
{
if(j == 0 || str.ch[i] == substr.ch[j])
{
++i;
++j;
}
else
j = next;
}
if(j > substr.length)
return i - substr.length;
else
return -;
}
采用定长顺序存储表示串,编写一个函数,删除从下表为i的字符开始的j个字符,如果i后面的字符串不足j个,有几个删几个
算法思想:从下标为i+j个字符开始,将所有的字符向前移动j个单位,然后将字符串进行调整。
void delIJ(Str &str, int i, int j)
{
if (i < str.length && i >= 0 && j >= 0)
{
for (int k = i + j; k < str.length; ++k)
{
str.ch[k - j] = str.ch[k];
str.length -= (str.length - i < j ? str.length - i : j);
// 调整字符串长度,注意要求
str.ch[str.length] = '\0';
}
}
}
采用顺序存储方式存储串,编写一个函数,将串str1中的下标i到下标j之间的字符用str2替换
算法思想:取str1中0到i-1位置上的子串str11,取str1中j到串尾的子串str12,最后连接str11、str2、str12
这道题我需要冷静一下,真的需要这么复杂吗?
计算一个子串在一个主串中出现的次数,如果该子串不出现,则返回0。不考虑子串重叠
int index(Str str, Str substr)
{
int i = 1, j = 1, k = 1, sum = 0;
while (i <= str.length)
{
if (str.ch[i] == substr.ch[j])
{
++i;
++j;
}
else
{
j = 1;
i = ++k; // 匹配失败,i从主串下一位置开始,k中记录了上一次的起始位置
}
if (j > substr.length)
{
j = 1;
++sum;
}
}
return sum;
}
构造串的链表结点数据结构(每个节点内存储一个字符),编写函数,找出串str1中第一个不在str2中出现的字符
typedef struct SNode
{
char data;
struct SNode *next;
}SNode;
char findfirst(SNode* str1, SNode*str2)
{
for (SNode* p = str1; p != NULL; p = p->next)
{
bool flag = false;
for (SNode* q = str1; q != NULL; q = q->next)
{
if(p->data == q->data)
{
flag = true;
break;
}
}
if(flag == false)
return p->data;
}
return '\0';
}