PTA数据结构与算法题目集(中文)的函数题部分。本身底子就差,还有好多语法知识都快忘了,这里写出来相当于一个查漏补缺了。不能一蹴而就。
文章目录
6-1 单链表逆转
图解
用头插法去做,1->3中,1被取出作为头,接着3被取出放在1的前面作为新头。但是要注意顺序,这个容易出错!!!
另外就是结构体链表的创建和输出。
#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 Reverse( List L );
int main()
{
List L1, L2;
L1 = Read();
L2 = Reverse(L1);
Print(L1);
Print(L2);
return 0;
}
/* 你的代码将被嵌在这里 */
List Reverse( List L )
{
List N = NULL; //结构体指针,新表头
List p = NULL; //头插法指针
while(L)
{
p = L;
L = L->Next; //为啥要放在这里?!
p->Next = N; //!!!这里改变了
printf("%d\n", p->Data);
N = p;
//L = L->Next; //放在这个地方是错的
}
return N;
}
List Read()
{
List L = (List)malloc(sizeof(struct Node));//创建头结点
List beg = L;
int n = 0;
scanf("%d", &n);
scanf("%d", &L->Data);
List p = NULL; //临时指针
for(int i=0;i<n-1;i++){ //循环建立数据结点
p = (List)malloc(sizeof(struct Node));
//将结点s插在原开始节点之前,头结点之后
scanf("%d", &p->Data);
//L一直指向最后一个节点,而的指针beg才是指向链表头结点的
L->Next = p;
L = L->Next;
}
L->Next = NULL;
return beg;
}
void Print( List L )
{
while(L)
{
printf("%d",L->Data);
L = L->Next;
}
printf("\n");
}
6-2 顺序表操作集
顺序表有些小小的特征,都在注释里
#include <stdio.h>
#include <stdlib.h>
#define MAXSIZE 5
#define ERROR -1
typedef enum {false, true} bool;
typedef int ElementType;
typedef int Position; //从0开始的
typedef struct LNode *List;
struct LNode {
ElementType Data[MAXSIZE]; //线性表是紧挨着的,中间没有空格
Position Last; /* 保存线性表中最后一个元素的位置 */
};
List MakeEmpty();
Position Find( List L, ElementType X );
bool Insert( List L, ElementType X, Position P );
bool Delete( List L, Position P );
int main()
{
List L;
ElementType X;
Position P;
int N;
L = MakeEmpty();
//printf("L:::%d\n", L->Last);
scanf("%d", &N);
while ( N-- ) {
scanf("%d", &X);
if ( Insert(L, X, 0)==false )
printf(" Insertion Error: %d is not in.\n", X);
}
//printf("LNEXT:::%d\n", L->Last); //为啥这里的last变了,啊啊啊,因为初始化的时候应该是-1
scanf("%d", &N);
while ( N-- ) {
scanf("%d", &X);
P = Find(L, X);
if ( P == ERROR )
printf("Finding Error: %d is not in.\n", X);
else
printf("%d is at position %d.\n", X, P);
}
scanf("%d", &N);
while ( N-- ) {
scanf("%d", &P);
if ( Delete(L, P)==false )
printf(" Deletion Error.\n");
if ( Insert(L, 0, P)==false )
printf(" Insertion Error: 0 is not in.\n");
}
return 0;
}
/* 你的代码将被嵌在这里 */
List MakeEmpty()
{
List L = (List)malloc(sizeof(struct LNode));
L->Last = -1;
return L;
}
Position Find( List L, ElementType X )
{
Position n = 0;
//printf("L:::%d", L->Last);
while(n <= L->Last)
{
if(L->Data[n] == X)
{
return n;
}
//printf(":::%d", n);
n++;
}
//printf("L:::%d", L->Last);
return ERROR;
}
/*
顺序表中插入数据元素,无非三种情况:
在表头插入;
在表的中间某个位置插入;
直接尾随顺序表,作为表的最后一个元素;
无论在顺序表的什么位置插入数据元素,解决办法都是:找到要插入的位置,
将后续数据元素整体向后移动一个位置,最后直接在腾出来的位置上插入指定的数据元素。
*/
bool Insert( List L, ElementType X, Position P )
{ //插入的话要把后面的往后挪
if(L->Last+1 >= MAXSIZE)
{
printf("FULL");
return false;
}
else if(P > L->Last+1)
{
printf("ILLEGAL POSITION");
return false;
}
else
{
int tmp;//暂存往后挪的那个数字
L->Last += 1;
while(P < L->Last)
{
tmp = L->Data[P];
L->Data[P] = X;
X = tmp;
P++;
}
L->Data[P] = X;
//printf("L:::%d\n", L->Last);
return true;
}
}
bool Delete( List L, Position P )
{
if(P > L->Last || P < 0)
{
printf("POSITION %d EMPTY", P);
return false;
}
L->Last = L->Last-1;
while(P <= L->Last)
{
L->Data[P] = L->Data[P+1];
}
return true;
}
6-3 求链式表的表长
读到-1时停止输入
#include <stdio.h>
#include <stdlib.h>
typedef int ElementType;
typedef struct LNode *PtrToLNode;
struct LNode {
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode List;
List Read(); /* 细节在此不表 */
int Length( List L );
int main()
{
List L = Read();
printf("%d\n", Length(L));
return 0;
}
List Read()
{
List L = (List)malloc(sizeof(struct LNode));
List beg = L;
int n = 0;
List p = NULL; //临时指针
scanf("%d", &n);
if(n != -1)
L->Data = n;
scanf("%d", &n);
while(n != -1 )
{
p = (List)malloc(sizeof(struct LNode));
p->Data = n;
L->Next = p;
L = L->Next;
scanf("%d", &n);
}
L->Next = NULL;
//printf("finish\n");
return beg;
}
/* 你的代码将被嵌在这里 */
int Length( List L )
{
int sum = 0;
while(L)
{
sum++;
L = L->Next;
}
return sum;
}
6-4 链式表的按序号查找
#include <stdio.h>
#include <stdlib.h>
#define ERROR -1
typedef int ElementType;
typedef struct LNode *PtrToLNode;
struct LNode
{
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode List;
List Read(); /* 细节在此不表 */
ElementType FindKth( List L, int K );
int main()
{
int N, K;
ElementType X;
List L = Read();
scanf("%d", &N);
while ( N-- )
{
scanf("%d", &K);
X = FindKth(L, K);
if ( X!= ERROR )
printf("%d ", X);
else
printf("NA ");
}
return 0;
}
List Read()
{
List L = (List)malloc(sizeof(struct LNode));
List beg = L;
int n = 0;
List p = NULL; //临时指针
scanf("%d", &n);
if(n != -1)
L->Data = n;
scanf("%d", &n);
while(n != -1 )
{
p = (List)malloc(sizeof(struct LNode));
p->Data = n;
L->Next = p;
L = L->Next;
scanf("%d", &n);
}
L->Next = NULL;
//printf("finish\n");
return beg;
}
/* 你的代码将被嵌在这里 */
ElementType FindKth( List L, int K )
{
int num = 1;
while(L)
{
if(num == K)
{
return L->Data;
}
L = L->Next; //注意是指向新节点后就要判断是否为空
num++;
}
return ERROR;
}
6-5 链式表操作集
#include <stdio.h>
#include <stdlib.h>
#define ERROR NULL
typedef int ElementType;
typedef struct LNode *PtrToLNode;
struct LNode
{
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;
Position Find( List L, ElementType X );
List Insert( List L, ElementType X, Position P );
List Delete( List L, Position P );
void Print( List L );
int main()
{
List L;
ElementType X;
Position P, tmp;
int N;
L = NULL;
scanf("%d", &N);
while ( N-- )
{
scanf("%d", &X);
L = Insert(L, X, L);
if ( L==ERROR )
printf("Wrong Answer\n");
}
//Print( L );
//printf("--------------");
scanf("%d", &N);
while ( N-- )
{
scanf("%d", &X);
P = Find(L, X);
if ( P == ERROR )
printf("Finding Error: %d is not in.\n", X);
else
{
L = Delete(L, P);
printf("%d is found and deleted.\n", X);
if ( L==ERROR )
printf("Wrong Answer or Empty List.\n");
}
}
L = Insert(L, X, NULL);
if ( L==ERROR )
printf("Wrong Answer\n");
else
printf("%d is inserted as the last element.\n", X);
P = (Position)malloc(sizeof(struct LNode));
tmp = Insert(L, X, P);
if ( tmp!=ERROR )
printf("Wrong Answer\n");
tmp = Delete(L, P);
if ( tmp!=ERROR )
printf("Wrong Answer\n");
for ( P=L; P; P = P->Next )
printf("%d ", P->Data);
return 0;
}
void Print( List L )
{
while(L)
{
printf("%d",L->Data);
L = L->Next;
}
printf("\n");
}
/* 你的代码将被嵌在这里 */
Position Find( List L, ElementType X )
{
List pos = L;
while(pos)
{
if(pos->Data == X)
{
return pos;
}
pos = pos->Next;
}
return ERROR;
}
List Insert( List L, ElementType X, Position P )
{
List pos = L;
List node = (List)malloc(sizeof(struct LNode));
node->Data = X;
if(L == P)
{
node->Next = pos;
return node;
}
while(pos)
{
if(pos->Next == P)
{
node->Next = pos->Next;
pos->Next = node;
return L;
}
pos = pos->Next;
}
printf("Wrong Position for Insertion\n");
return ERROR;
}
List Delete( List L, Position P )
{
List pos = L;
if(L == P)
{
return L->Next;
}
while(pos)
{
if(pos->Next == P)
{
//删除时要找到前一个
pos->Next = P->Next;
return L;
}
pos = pos->Next;
}
printf("Wrong Position for Deletion\n");
return ERROR;
}
6-6 带头结点的链式表操作集
#include <stdio.h>
#include <stdlib.h>
#define ERROR NULL
typedef enum {false, true} bool;
typedef int ElementType;
typedef struct LNode *PtrToLNode;
struct LNode {
ElementType Data;
PtrToLNode Next;
};
typedef PtrToLNode Position;
typedef PtrToLNode List;
List MakeEmpty();
Position Find( List L, ElementType X );
bool Insert( List L, ElementType X, Position P );
bool Delete( List L, Position P );
int main()
{
List L;
ElementType X;
Position P;
int N;
bool flag;
L = MakeEmpty();
scanf("%d", &N);
while ( N-- ) {
scanf("%d", &X);
flag = Insert(L, X, L->Next);
if ( flag==false ) printf("Wrong Answer\n");
}
scanf("%d", &N);
while ( N-- ) {
scanf("%d", &X);
P = Find(L, X);
if ( P == ERROR )
printf("Finding Error: %d is not in.\n", X);
else {
flag = Delete(L, P);
printf("%d is found and deleted.\n", X);
if ( flag==false )
printf("Wrong Answer.\n");
}
}
flag = Insert(L, X, NULL);
if ( flag==false ) printf("Wrong Answer\n");
else
printf("%d is inserted as the last element.\n", X);
P = (Position)malloc(sizeof(struct LNode));
flag = Insert(L, X, P);
if ( flag==true ) printf("Wrong Answer\n");
flag = Delete(L, P);
if ( flag==true ) printf("Wrong Answer\n");
for ( P=L->Next; P; P = P->Next ) printf("%d ", P->Data);
return 0;
}
/* 你的代码将被嵌在这里 */
List MakeEmpty()
{
List node = (List)malloc(sizeof(struct LNode));
node->Next = NULL;
return node;
}
Position Find( List L, ElementType X )
{
List pos = L->Next;
while(pos)
{
if(pos->Data == X)
{
return pos;
}
pos = pos->Next;
}
return ERROR;
}
bool Insert( List L, ElementType X, Position P )
{
List pos = L->Next;
List node = (List)malloc(sizeof(struct LNode));
node->Data = X;
if(pos == P)
{
node->Next = pos;
L->Next = node;
return true;
}
while(pos)
{
if(pos->Next == P)
{
node->Next = pos->Next;
pos->Next = node;
return true;
}
pos = pos->Next;
}
printf("Wrong Position for Insertion\n");
return false;
}
bool Delete( List L, Position P )
{
List pos = L->Next;
if(pos == P)
{
L->Next = pos->Next;
return true;
}
while(pos)
{
if(pos->Next == P)
{
//删除时要找到前一个
pos->Next = P->Next;
return true;
}
pos = pos->Next;
}
printf("Wrong Position for Deletion\n");
return false;
}
6-7 在一个数组中实现两个堆栈
必须检查Stack是否为NULL,要不然一个测试案例都过不了
Stack CreateStack( int MaxSize )
{
Stack s = (Stack)malloc(sizeof(struct SNode));
s->MaxSize = MaxSize;
//动态开辟一个数组
s->Data = (ElementType*)malloc(MaxSize*sizeof(ElementType));
//栈底就是数组的两个边界
s->Top1 = -1;
s->Top2 = MaxSize;
return s;
}
bool Push( Stack S, ElementType X, int Tag )
{
if (!S) return false;
if(S->Top1+1 == S->Top2)
{
printf("Stack Full\n");
return false;
}
if(Tag == 1)
{
S->Data[++S->Top1] = X;
}
else
{
S->Data[--S->Top2] = X;
}
return true;
}
ElementType Pop( Stack S, int Tag )
{
if (!S) return ERROR;
if(Tag == 1)
{
if(S->Top1 == -1)
{
printf("Stack 1 Empty\n");
return ERROR;
}
return S->Data[S->Top1--];
}
else
{
if(S->Top2 == S->MaxSize)
{
printf("Stack 2 Empty\n");
return ERROR;
}
return S->Data[S->Top2++];
}
}
6-8 求二叉树高度
我们一定要考虑几个条件:
- 二叉树空 return 0
- 只有一个节点的情况
- 一般情况
if (ch=='#')
{//没孩子
BT=NULL;
}
else
{
BT=(BinTree)malloc(sizeof(BinTree));
BT->Data=ch;
CreatBinTree(BT->Left);
CreatBinTree(BT->Right);
}
当用先序创造一棵树时,可以画出递归函数的前进:
计算树的高度,每次左右节点递归完,到中间节点处要做个比较。
int GetHeight( BinTree BT )
{
if (!BT) return 0;
else
{
int left = GetHeight( BT->Left )+1;
int right = GetHeight( BT->Right )+1;
return (left>right) ? left : right;
}
}
6-9 二叉树的遍历
//前中后序遍历都是有规律的
void InorderTraversal( BinTree BT )
{//中序
if(!BT)
{
return;
}
InorderTraversal( BT->Left );
printf(" %c",BT->Data);
InorderTraversal( BT->Right );
}
void PreorderTraversal( BinTree BT )
{//前序
if(!BT)
{
return;
}
printf(" %c",BT->Data);
PreorderTraversal( BT->Left );
PreorderTraversal( BT->Right );
}
void PostorderTraversal( BinTree BT )
{//后序
if(!BT)
{
return;
}
PostorderTraversal( BT->Left );
PostorderTraversal( BT->Right );
printf(" %c",BT->Data);
}
void LevelorderTraversal( BinTree BT )
{
// 所以说队列还是很好写的
if(BT == NULL)
{
return;
}
BinTree queen[100];
int front=0,rear=0;
//queen[0] = BT; //不能这么写,要不然进不了循环
queen[rear++] = BT;
while(front != rear)
{
BT = queen[front++];//段错误?因为没写而这句话
if(BT->Left)
queen[rear++] = BT->Left;
if(BT->Right)
queen[rear++] = BT->Right;
printf(" %c", BT->Data);
}
}
但是构造一棵树的时候用到了引用
所以要换到cpp里运行检查错误
void CreatBinTree(BinTree &BT)
{//CreatBinTree(BT);这样写BT是个空的
char ch;
scanf("%c", &ch);
if (ch=='#')
{
//没孩子
BT=NULL;
}
else
{
BT = (BinTree)malloc(sizeof(BinTree));
BT->Data = ch;
CreatBinTree(BT->Left);
CreatBinTree(BT->Right);
}
}
6-10 二分查找
Position BinarySearch( List L, ElementType X )
{
//元素从下标1开始存储
if(!L){return NotFound;}
Position min = 1;
Position max = L->Last;
Position now;
while(min <= max)
{
now = (min+max)/2;
if(L->Data[now] > X)
{
max = now-1;
}
else if(L->Data[now] < X)
{
min = now+1;
}
else
{
return now;
}
}
return NotFound;
}
6-11 先序输出叶结点
void PreorderPrintLeaves( BinTree BT )
{
if(!BT){return;}
if(!BT->Left && !BT->Right)
{
printf(" %c", BT->Data);
return;
}
PreorderPrintLeaves(BT->Left);
PreorderPrintLeaves(BT->Right);
}
6-12 二叉搜索树的操作集
二叉搜索树又叫「平衡二叉树」。
它的特点:左子树<根<右子树。
先放除了删除部分的代码:
#include <stdio.h>
#include <stdlib.h>
typedef int ElementType;
typedef struct TNode *Position;
typedef Position BinTree;
struct TNode
{
ElementType Data;
BinTree Left;
BinTree Right;
};
void PreorderTraversal( BinTree BT ); /* 先序遍历,由裁判实现,细节不表 */
void InorderTraversal( BinTree BT ); /* 中序遍历,由裁判实现,细节不表 */
BinTree Insert( BinTree BST, ElementType X );
BinTree Delete( BinTree BST, ElementType X );
Position Find( BinTree BST, ElementType X );
Position FindMin( BinTree BST );
Position FindMax( BinTree BST );
int main()
{
BinTree BST, MinP, MaxP, Tmp;
ElementType X;
int N, i;
BST = NULL;
scanf("%d", &N);
for ( i=0; i<N; i++ )
{
scanf("%d", &X);
BST = Insert(BST, X);
}
printf("Preorder:");
PreorderTraversal(BST);
printf("\n");
MinP = FindMin(BST);
MaxP = FindMax(BST);
scanf("%d", &N);
for( i=0; i<N; i++ )
{
scanf("%d", &X);
Tmp = Find(BST, X);
if (Tmp == NULL)
printf("%d is not found\n", X);
else
{
printf("%d is found\n", Tmp->Data);
if (Tmp==MinP)
printf("%d is the smallest key\n", Tmp->Data);
if (Tmp==MaxP)
printf("%d is the largest key\n", Tmp->Data);
}
}
scanf("%d", &N);
for( i=0; i<N; i++ )
{
scanf("%d", &X);
BST = Delete(BST, X);
}
printf("Inorder:");
InorderTraversal(BST);
printf("\n");
return 0;
}
void InorderTraversal( BinTree BT )
{
//中序
if(!BT)
{
return;
}
InorderTraversal( BT->Left );
printf(" %d",BT->Data);
InorderTraversal( BT->Right );
}
void PreorderTraversal( BinTree BT )
{
//前序
if(!BT)
{
return;
}
printf(" %d",BT->Data);
PreorderTraversal( BT->Left );
PreorderTraversal( BT->Right );
}
/* 你的代码将被嵌在这里 */
BinTree Insert( BinTree BST, ElementType X )
{
BinTree node = (BinTree)malloc(sizeof(struct TNode));
node->Data = X;
node->Left = NULL;
node->Right = NULL;
if(!BST)
{
return node;
}
BinTree p = BST;
while(1)
{
if(p->Data > X)
{
if(!p->Left)
{
p->Left = node;
return BST;
}
p = p->Left;
}
else if(p->Data < X)
{
if(!p->Right)
{
p->Right = node;
return BST;
}
p = p->Right;
}
}
}
Position Find( BinTree BST, ElementType X )
{
BinTree p = BST;
while(p)
{
if(p->Data > X)
{
p = p->Left;
}
else if(p->Data < X)
{
p = p->Right;
}
else
{
return p;
}
}
return NULL;
}
Position FindMin( BinTree BST )
{
if (!BST)
{
return NULL;
}
while (BST->Left)
{
BST=BST->Left;
}
return BST;
}
Position FindMax( BinTree BST )
{
if (!BST)
{
return NULL;
}
while (BST->Right)
{
BST=BST->Right;
}
return BST;
}
解决了为啥不能随便删的疑惑以及有两个子节点,用左儿子或者右儿子的值替换改节点的值,然后删除那个叶子节点。注意用节点的值替换不必用节点替换。
进一步简化:有两个子节点,将右子树最小值替换当前root值,或者左子树最大值去替换,然后删掉那个最小值叶节点。
BinTree Delete( BinTree BST, ElementType X )
{
//查找,正是因为递归才能保留双亲节点
//如果用Find查找返回一个新指针,是没法改变值的
if (!BST)
{
//当递归找到空节点或者本身为空时就退出
printf("Not Found\n");
return NULL;
}
else if (X > BST->Data)
{
BST->Right = Delete(BST->Right, X);
}
else if (X < BST->Data)
{
BST->Left = Delete(BST->Left, X);
}
//找到了
else if(X == BST->Data)
{
Position tmp;
if (BST->Left && BST->Right)
{//左右双亲都有
tmp = FindMin(BST->Right);
BST->Data = tmp->Data;
//替换掉值之后的任务就是,把用来替换那个删掉(但是递归你不用考虑是怎么被删掉的)
BST->Right = Delete(BST->Right, BST->Data);
}
else
{
if (BST->Left == NULL)
BST = BST->Right;
else if (BST->Right == NULL)
BST = BST->Left;
else
free(BST);
}
}
return BST;
}
如果不用递归去做,那么删除的时候不能用Find函数之类的了,因为你的拿到双亲节点,也就不能只是替换节点的值那么简单了。
BinTree Delete( BinTree BST, ElementType X )
{
if(!BST)
{
//空的直接不找了
printf("Not Found\n");
return BST;
}
//由于删除的时候要保留前一个节点,寻找就不能调用那个寻找函数了
BinTree p = BST;
BinTree parent = NULL;
while(1)
{
//找节点,按照道理找不到就退出循环
if (X > p->Data)
{
if(p->Right != NULL)
{
parent = p;
p = p->Right;
}
else
break;
}
else if (X < p->Data)
{
if(p->Left != NULL)
{
parent = p;
p = p->Left;
}
else
break;
}
//找到了节点,分情况删除
else if (X == p->Data)
{
//当为叶结点时
if(p->Left == NULL && p->Right == NULL)
{
if(parent->Left == p)
{
parent->Left = NULL;
}
else if(parent->Right == p)
{
parent->Right = NULL;
}
else //没有双亲,是个单独的节点
return NULL;
}
//当为一个子结点时
else if(p->Left == NULL)
{
if(parent == NULL)
{
return p->Right;
}
else if(parent->Left == p)
{
parent->Left = p->Right;
}
else
{
parent->Right = p->Right;
}
}
else if(p->Right == NULL)
{
if(parent == NULL)
{
return p->Left;
}
else if(parent->Left == p)
{
parent->Left = p->Left;
}
else
{
parent->Right = p->Left;
}
}
else
{
//非递归的方法就得额外保存双亲,不是仅仅替换值就可以了。
BinTree tmp = FindMin(p->Right);
p->Data = tmp->Data;
//tmp = NULL; //这样是错的
//去置空孩子节点
p = p->Right;
while (p->Left != tmp)
{
p = p->Left;
}
//此时被删除的点p->Left一定是没有左孩子的,但可能有右孩子
if(p->Left->Right != NULL)
{
p->Left = p->Left->Right;
}
else
p->Left = NULL;
}
return BST;
}
}
printf("Not Found\n");
return BST;
}
这道题的一些测试数据:
1
7
2
5 9
3
5 9 7
5
5 4 3 2 1
2
6 -1
5
-1 6 5 1 3
总结
比起以前来说好多了,但还是菜,多练练吧。