《数据结构》C语言版——期末总复习(上篇)
《数据结构》C语言版——期末总复习(上篇)包括绪论、线性表、栈和队列、串和数组共四章。
如需获取本书请点击链接
第一章 绪论
- 数据项是数据的最小单位。
- 数据的逻辑结构是指反映数据元素之间逻辑关系的数据结构。
- 抽象数据结构与计算机内部表示和实现无关。
- NlogN²和NlogN具有相同的增长速度,但N²logN和NlogN²具有不相同的增长速度。
- 数据结构在计算机内存中的表示是指数据的存储结构。
- 算法分析的目的是分析算法的效率以求改进。
- 一个正确的算法应该具有5个特性:输入、输出、确定、可行、有穷。
- 在数据结构中,从逻辑上可以把数据结构分为线性结构和非线性结构。
- 算法原地工作的含义是指不需要任何额外的辅助,算法所需要的辅助空间不随着时间的规模而变化,是一个确定值。
- 同一个算法,实现语言的级别越高,执行效率越低。
- 算法效率的比较:
O(1) > O(log2n) > O(√n) > O(n) > O(nlog2n) > O(n√n) > O(n²) > O(2) > O(n!) > O(nⁿ)
第二章 线性表
- 顺序存储方式的优点主要有:存储密度大,存储空间利用率高,便于随机存储。
- 对于顺序存储的长度为N的线性表,访问结点和增加结点的时间复杂度分别对应为O(1)和O(N)。
- 若某线性表最常用的操作是存取任一指定序号的元素和在最后进行插入和删除运算,则利用顺序表存储最节省时间。
- 单链表的存储密度小于1。
- 将两个结点数都为N且都从小到大有序的单向链表合并成一个从小到大有序的单向链表,那么可能的最少比较次数是2N。
- 创建一个包括n个结点的有序单链表的时间复杂度是O(n²)。
- 设一个链表最常用的操作是在末尾插入结点和删除尾结点,则选用带头结点的双循环链表最节省时间。
- 对于双向链表,在两个结点之间插入一个新结点需修改的指针共4个,单链表为2个。
第三章 栈和队列
1.两个栈共享一片连续空间,可以将两个栈的栈底分别设在这片空间的两端。
2.栈在递归调用、函数调用、表达式求值中有所应用。
3.队空条件:rear=front; 队满条件:(rear+1)%MAXSIZE=front。
第四章 串、数组和广义表
由于学校老师没有要求学习广义表,所以没有对广义表进行复习。
- 串是一种特殊的线性表,其特殊性体现在数据元素是一个字符。
- 串既可以采用顺序存储,也可以采用链式存储。
- 设有两个串p和q,求q在p中首次出现的位置的运算称作模式匹配。
- 稀疏矩阵是一种特殊矩阵,其特点为非零元素的个数远远小于零元素的个数。
- 对特殊矩阵采用压缩后,和直接采用二维数组相比会失去随机存取的特性。
第二章线性表例题
7-1 一元多项式求导 (15分)
设计函数求一元多项式的导数。
输入格式:
以指数递降方式输入多项式非零项系数和指数(绝对值均为不超过1000的整数)。数字间以空格分隔。
#include <stdio.h>
void main()
{
int number1,number2,count = 0;
while (scanf("%d %d", &number1, &number2) != EOF) {
if (number2) {
if (count == 0)
printf("%d %d", number1 * number2, number2 - 1);
else
printf(" %d %d", number1 * number2, number2 - 1);
count++;
}
else if(count != 0)
break;
else
printf("0 0");
}
system("pause");
}
6-9 两个有序链表序列的合并 (10分)
本题要求实现一个函数,将两个链表表示的递增整数序列合并为一个非递减的整数序列.
List Merge( List L1, List L2 )
{
struct Node *L,*p,*q,*k;
L = (struct Node*)malloc(sizeof(struct Node));
p = L1->Next;
q = L2->Next;
k = L;
while(p && q)
{
if(p->Data <= q->Data)
{
k->Next = p;
k = p;
p = p->Next;
}
else
{
k->Next = q;
k = q;
q = q->Next;
}
}
if(p == NULL)
{
k->Next = q;
}
else if(q == NULL)
{
k->Next = p;
}
L1->Next = NULL;
L2->Next = NULL;
return L;
}
第三章栈和队列例题
7-3 两个有序链表序列的合并 (9分)
已知两个非降序链表序列S1与S2,设计函数构造出S1与S2合并后的新的非降序链表S3。
#include <stdio.h>
#include <stdlib.h>
typedef int ElementType;
typedef struct Node *PtrToNode;
struct Node {
ElementType Data;
PtrToNode Next;
};
typedef PtrToNode List;
List Read();
void Print(List L);
List Merge(List L1, List L2);
int main()
{
List L1, L2, L;
L1 = Read();
L2 = Read();
L = Merge(L1, L2);
Print(L);
system("pause");
return 0;
}
List Read()
{
int data;
List p, q;
List L = (struct Node *)malloc(sizeof(struct Node));
L->Next = NULL;
p = L;
scanf("%d", &data);
while (data != -1) {
q = (struct Node *)malloc(sizeof(struct Node));
q->Data = data;
q->Next = p->Next;
p->Next = q;
p = q;
scanf("%d", &data);
}
return L;
}
List Merge(List L1, List L2)
{
struct Node *L, *p, *q, *k;
L = (struct Node*)malloc(sizeof(struct Node));
p = L1->Next;
q = L2->Next;
k = L;
while (p && q)
{
if (p->Data <= q->Data)
{
k->Next = p;
k = p;
p = p->Next;
}
else
{
k->Next = q;
k = q;
q = q->Next;
}
}
if (p == NULL)
{
k->Next = q;
}
else if (q == NULL)
{
k->Next = p;
}
L1->Next = NULL;
L2->Next = NULL;
return L;
}
void Print(List L)
{
int count = 0;
List p;
p = L->Next;
if (L->Next == NULL)
printf("NULL");
while (p) {
if (count == 0) {
printf("%d", p->Data);
count++;
}
else
printf(" %d", p->Data);
p = p->Next;
}
}
7-5 数组循环左移 (8分)
本题要求实现一个对数组进行循环左移的简单函数:一个数组a中存有n(>0)个整数,在不允许使用另外数组的前提下,将每个整数循环向左移m(≥0)个位置,即将a中的数据由(a
0
a
1
⋯a
n−1
)变换为(a
m
⋯a
n−1
a
0
a
1
⋯a
m−1
)(最前面的m个数循环移至最后面的m个位置)。如果还需要考虑程序移动数据的次数尽量少,要如何设计移动的方法?
#include <stdio.h>
int main()
{
int number, position,i;
scanf("%d%d", &number, &position);
int array[200];
for (i = 0; i < number; i++) {
scanf("%d", &array[i]);
}
for (i = 0; i < position; i++) {
array[number + i] = array[i];
}
for (i; i < position + number;i++) {
if (i == position) {
printf("%d", array[i]);
}
else {
printf(" %d", array[i]);
}
}
system("pause");
return 0;
}
6-1 另类堆栈 (7分)
在栈的顺序存储实现中,另有一种方法是将Top定义为栈顶的上一个位置。请编写程序实现这种定义下堆栈的入栈、出栈操作。如何判断堆栈为空或者满?
bool Push(Stack S, ElementType X)
{
if (S->Top == S->MaxSize) {
printf("Stack Full\n");
return false;
}
S->Data[S->Top] = X;
S->Top++;
return true;
}
ElementType Pop(Stack S)
{
int data;
if (S->Top == 0) {
printf("Stack Empty\n");
return ERROR;
}
S->Top--;
data = S->Data[S->Top];
return data;
}
6-2 十进制转二进制(顺序栈设计和应用) (7分)
设计一个顺序栈,并利用该顺序栈将给定的十进制整整数转换为二进制并输出。
bool isEmpty()
{
if (top == -1)
return true;
return false;
}
void Push(int x)
{
top++;
mystack[top] = x;
}
int getTop()
{
int e = mystack[top];
return e;
}
void Pop()
{
top--;
}
7-2 括号匹配 (11分)
给定一串字符,不超过100个字符,可能包括括号、数字、字母、标点符号、空格,编程检查这一串字符中的( ) ,[ ],{ }是否匹配。
输入格式:
输入在一行中给出一行字符串,不超过100个字符,可能包括括号、数字、字母、标点符号、空格。
#include<stdio.h>
#include<stdlib.h>
#define MAXSIZE 200
typedef struct node
{
int top;
char data[MAXSIZE];
}SqStack;
SqStack *creat()
{
SqStack *s = (SqStack *)malloc(sizeof(SqStack));
s->top = -1;
return s;
}
void push(SqStack *s,char ch1)
{
s->top++;
s->data[s->top]=ch1;
}
int main()
{
int i,flag=1;
char ch[MAXSIZE],ch1[MAXSIZE];
gets(ch);
ch1['(']=')';
ch1['{']='}';
ch1['[']=']';
SqStack *s;
s=creat();
for(i=0;ch[i]!='\0';i++)
{
if(ch[i]=='{'||ch[i]=='['||ch[i]=='(')
{
push(s,ch[i]);
}
else if(ch[i]==')'||ch[i]=='}'||ch[i]==']')
{
if(s->top != -1 && ch1[s->data[s->top]] == ch[i])
{
s->top--;
}
else
{
flag = 0;
break;
}
}
}
if(flag == 1 && s->top == -1)
printf("yes\n");
else
printf("no\n");
return 0;
}
7-3 表达式求值_1 (20分)
在一个表达式中,只有“(”,“)”,“0-9”,“+”,“-”,“*”,“/”,“^”,请求出表达式的值。(“/”用整数除法)。
输入格式:
共1 行,为一个算式。 (算式长度<=30 其中所有数据在 0~2^31-1的范围内)。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
int IfNum(char ch);
int Calculate(int a,char ch,int b);
int Comparechar(char a,char b);
int main()
{
char s[310];
int operand[310];
char coperator[310];
gets(s);
int topo,topc;
topo = 0;
topc = 0;
for (int i = 0;i < 310;i++)
{
operand[i] = 0;
coperator[i] = '0';
}
int i = 0;
while (i < strlen(s)){
if (IfNum(s[i])){
while (IfNum(s[i]))
operand[topo] = operand[topo] * 10 + s[i++] - '0';
topo++;
continue;
}
else{
if (s[i] == '(')
coperator[topc++] = s[i];
else if(s[i] == ')'){
while (coperator[topc - 1] != '('){
operand[topo - 2] = Calculate(operand[topo - 2], coperator[topc - 1], operand[topo - 1]);
operand[topo - 1] = 0;
topc--;
topo--;
}
topc--;
}
else{
if (topc == 0)
coperator[topc++] = s[i];
else if (Comparechar(s[i], coperator[topc - 1]))
coperator[topc++] = s[i];
else{
while (!Comparechar(s[i], coperator[topc - 1])){
if (coperator[topc - 1] == '(')
break;
operand[topo - 2] = Calculate(operand[topo - 2], coperator[topc - 1], operand[topo - 1]);
operand[topo - 1] = 0;
topc--;
topo--;
if (topc == 0)
break;
}
coperator[topc++] = s[i];
}
}
}
i++;
}
while (topo != 1 && topc > 0){
operand[topo - 2] = Calculate(operand[topo - 2], coperator[topc - 1], operand[topo - 1]);
topo--;
topc--;
}
printf("%d",operand[0]);
}
int IfNum(char coperator)
{
if(coperator <= '9' && coperator >= '0')
return 1;
return 0;
}
int Calculate(int a,char coperator,int b)
{
if(coperator=='*')
return a*b;
else if(coperator=='/')
return a/b;
else if(coperator=='-')
return a-b;
else if(coperator=='+')
return a+b;
else
return pow(a,b);
}
int Comparechar(char a,char b)
{
int x = 0;
int y = 0;
if(a == '+' || a == '-')
x=1;
else if(a=='*'|| a=='/')
x=2;
else if(a=='^')
x=3;
else if(a=='(')
x=4;
if(b=='+'||b=='-')
y=1;
else if(b=='*'||b=='/')
y=2;
else if(b=='^')
y=3;
else if(b=='(')
y=4;
if(x > y)
return 1;
return 0;
}
7-4 银行业务队列简单模拟 (18分)
设某银行有A、B两个业务窗口,且处理业务的速度不一样,其中A窗口处理速度是B窗口的2倍 —— 即当A窗口每处理完2个顾客时,B窗口处理完1个顾客。给定到达银行的顾客序列,请按业务完成的顺序输出顾客序列。假定不考虑顾客先后到达的时间间隔,并且当不同窗口同时处理完2个顾客时,A窗口顾客优先输出。
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 1000
typedef struct node
{
int number[MAXSIZE];
int front;
int rear;
}SqQueue;
SqQueue *CreateQueue();
SqQueue * push(SqQueue *s, int n);
void pop(SqQueue *s1,SqQueue *s2);
int main()
{
int N;
SqQueue *A, *B;
A = CreateQueue();
B = CreateQueue();
scanf("%d", &N);
for (int i = 0; i < N; i++) {
int n;
scanf("%d", &n);
if (n % 2 != 0) {
A = push(A, n);
}
else {
B = push(B, n);
}
}
pop(A, B);
system("pause");
return 0;
}
SqQueue *CreateQueue()
{
SqQueue *s = (SqQueue *)malloc(sizeof(SqQueue));
s->front = 0;
s->rear = 0;
return s;
}
SqQueue * push(SqQueue *s, int n)
{
s->number[s->rear] = n;
s->rear++;
return s;
}
void pop(SqQueue *s1, SqQueue *s2)
{
while (s2->front != s2->rear || s1->front != s1->rear) {
if (s1->front == s1->rear && s2->front != s2->rear) {//A为空,B不为空
if (s2->front == 0) {
printf("%d", s2->number[s2->front]);
s2->front++;
}
else {
printf(" %d", s2->number[s2->front]);
s2->front++;
}
}
else if (s1->front != s1->rear && s2->front == s2->rear) {//A不为空,B为空
if ((s1->rear - s1->front) % 2 == 0) {//A中偶数个数
if (s1->front == 0) {
printf("%d %d", s1->number[s1->front], s1->number[s1->front + 1]);
s1->front = s1->front + 2;
}
else {
printf(" %d %d", s1->number[s1->front], s1->number[s1->front + 1]);
s1->front = s1->front + 2;
}
}
else {//A中奇数个数
if (s1->front == 0) {
if (s1->rear - s1->front == 1) {
printf("%d", s1->front);
s1->front++;
}
else {
printf("%d %d", s1->number[s1->front], s1->number[s1->front + 1]);
s1->front = s1->front + 2;
}
}
else if(s1->front < s1->rear){
printf(" %d %d", s1->number[s1->front], s1->number[s1->front + 1]);
s1->front = s1->front + 2;
}
else {
printf(" %d", s1->number[--s1->front]);
}
}
}
else{//A,B都不为空
if ((s1->rear - s1->front) % 2 == 0) {//A中偶数个数
if (s1->front == 0) {
printf("%d %d", s1->number[s1->front], s1->number[s1->front + 1]);
s1->front = s1->front + 2;
}
else {
printf(" %d %d", s1->number[s1->front], s1->number[s1->front + 1]);
s1->front = s1->front + 2;
}
printf(" %d", s2->number[s2->front]);
s2->front++;
}
else {//A中奇数个数
if (s1->front == 0) {
if (s1->rear - s1->front == 1) {
printf("%d", s1->front);
s1->front++;
}
else {
printf("%d %d", s1->number[s1->front], s1->number[s1->front + 1]);
s1->front = s1->front + 2;
}
}
else if (s1->front < s1->rear - 1) {
printf(" %d %d", s1->number[s1->front], s1->number[s1->front + 1]);
s1->front = s1->front + 2;
}
else {
printf(" %d", s1->number[s1->front]);
s1->front++;
}
printf(" %d", s2->number[s2->front]);
s2->front++;
}
}
}
}
7-5 堆栈模拟队列 (17分)
设已知有两个堆栈S1和S2,请用这两个堆栈模拟出一个队列Q。
所谓用堆栈模拟队列,实际上就是通过调用堆栈的下列操作函数:
int IsFull(Stack S):判断堆栈S是否已满,返回1或0;
int IsEmpty (Stack S ):判断堆栈S是否为空,返回1或0;
void Push(Stack S, ElementType item ):将元素item压入堆栈S;
ElementType Pop(Stack S ):删除并返回S的栈顶元素。
实现队列的操作,即入队void AddQ(ElementType item)和出队ElementType DeleteQ()。
#include <stdio.h>
#include <stdlib.h>
int s1[100];
int s2[100];
int main() {
int N1, N2;
scanf("%d%d\n", &N1, &N2);
char ch;
int s1count = 0;
int s2count = 0;
scanf("%c", &ch);
while (ch != 'T') {
if (ch == 'A') {
int item;
scanf(" %d", &item);
if (s1count > 0 && s2count == N2) {
printf("ERROR:Full\n");
}
else if (s2count < N2) {
s2[s2count++] = item;
}
if (s2count == N2 && s1count == 0) {
while (s2count != 0) {
s1[s1count++] = s2[--s2count];
}
}
}
else if (ch == 'D') {
if (s1count == 0 && s2count != 0) {
while (s2count != 0) {
s1[s1count++] = s2[--s2count];
}
}
if (s1count == 0 && s2count == 0) {
printf("ERROR:Empty\n");
}
if (s1count != 0) {
printf("%d\n", s1[--s1count]);
}
if (s2count == N2 && s1count == 0) {
while (s2count != 0) {
s1[s1count++] = s2[--s2count];
}
}
}
scanf(" %c", &ch);
}
return 0;
}