今天是2021.1.27,我在看一本叫做《啊哈,算法》的书,这本书的内容十分的基础且有趣,是一本很好的入门算法书,最近几天我都在看它,并且把书中的代码都敲了敲,发现有些代码有一点问题,在这里我作了一些修改。
第 2 章:栈、队列、链表
第 4 节 链表(P44)
题目:
第一行给出一个整数n,第二行给出n个已经从小到大排好的数,第三行给出需要往这串数中插入的数a,输出仍符合从小到大排列的新的序列。
要求:不使用数组,使用链表
输入样例:
9
2 3 5 8 9 10 18 26 32
6
输出样例:
2 3 5 6 8 9 10 18 26 32
书上的代码
#include <stdio.h>
#include <stdlib.h>
//这里创建一个结构体用来表示链表的结点类型
struct node
{
int data;
struct node *next;
};
int main()
{
struct node *head,*p,*q,*t;
int i,n,a;
scanf("%d",&n);
head = NULL;//头指针初始为空
for(i=1;i<=n;i++)//循环读入n个数
{
scanf("%d",&a);
//动态申请一个空间,用来存放一个结点,并用临时指针p指向这个结点
p=(struct node *)malloc(sizeof(struct node));
p->data=a;//将数据存储到当前结点的data域中
p->next=NULL;//设置当前结点的后继指针指向空,也就是当前结点的下一个结点为空
if(head==NULL)
head=p;//如果这是第一个创建的结点,则将头指针指向这个结点
else
q->next=p;//如果不是第一个创建的结点,则将上一个结点的后继指针指向当前结点
q=p;//指针q也指向当前结点
}
scanf("%d",&a);//读入待插入的数
t=head;//从链表头部开始遍历
while(t!=NULL)//当没有到达链表尾部的时候循环
{
if(t->next->data > a)//如果当前结点下一个结点的值大于待插入数,将数插入到中间
{
p=(struct node *)malloc(sizeof(struct node));//动态申请一个空间,用来存放新增结点
p->data=a;
p->next=t->next;//新增结点的后继指针指向当前结点的后继指针所指向的结点
t->next=p;//当前结点的后继指针指向新增结点
break;//插入完毕退出循环
}
t=t->next;//继续下一个结点
}
//输出链表中的所有数
t=head;
while(t!=NULL)
{
printf("%d ",t->data);
t=t->next;//继续下一个结点
}
getchar();getchar();
return 0;
}
原代码不足之处:
没有考虑输入的数字为最小/最大的情况
比如:
4
1 2 3 45
或者
4
1 2 3 4
0
等情况
我的代码:
#include <stdlib.h>
#include <iostream>
using namespace std;
struct node
{
int data;
struct node *next;
};
int main()
{
struct node *head, *p, *q;
int n;
cin >> n;
int z;
head = NULL;
for (int i = 0; i < n; i++)
{
cin >> z;
q = (struct node *)malloc(sizeof(struct node));
q->data = z;
q->next = NULL;
if (head == NULL)
{
head = q;
p = q;
p->next = NULL;
}
else
{
p->next = q;
p = q;
p->next = NULL;
}
}
p = head;
cin >> z;
q = (node *)malloc(sizeof(node));
q->data = z;
int flag = 0;
if (p->data > z)//输入的数最小
{
q->next = p;
head = q;
flag = 1;
}
else
{
while (p->next != NULL)
{
if (p->next->data >= z)
{
q->next = p->next;
p->next = q;
flag = 1;
break;
}
p = p->next;
}
}
if (flag==0)//输入的数最大
{
p->next = q;
q->next = NULL;
}
p = head;
while (p != NULL)
{
cout << p->data << " ";
p = p->next;
}
system("pause");
return 0;
}
第 5 节 模拟链表
题目和样例与第4节相同,只不过这次要求用模拟链表的方式编写代码。
书本代码:
#include <stdio.h>
int main()
{
int data[101],right[101];
int i,n,t,len;
//读入已有的数
scanf("%d",&n);
for(i=1;i<=n;i++)
scanf("%d",&data[i]);
len=n;
//初始化数组right
for(i=1;i<=n;i++)
{
if(i!=n)
right[i]=i+1;
else
right[i]=0;
}
//直接在数组data的末尾增加一个数
len++;
scanf("%d",&data[len]);
//从链表的头部开始遍历
t=1;
while(t!=0)
{
if(data[right[t]]>data[len])//如果当前结点下一个结点的值大于待插入数,将数插入到中间
{
right[len]=right[t];//新插入数的下一个结点标号等于当前结点的下一个结点编号
right[t]=len;//当前结点的下一个结点编号就是新插入数的编号
break;//插入完成跳出循环
}
t=right[t];
}
//输出链表中所有的数
t=1;
while(t!=0)
{
printf("%d ",data[t]);
t=right[t];
}
getchar();
getchar();
return 0;
}
不足:
和第4节一样,没考虑输入的数据位于首尾的情况。
我的代码:
#include <iostream>
using namespace std;
int main()
{
int data[100], right[100];
int n;
cin >> n;
int i, flag = 0;
for (i = 0; i < n; i++)
{
cin >> data[i];
right[i] = i + 1;
}
right[i-1] = -1;
cin >> data[n];
if (data[n] <= data[0])
{
swap(data[n], data[0]);
right[n] = n;
swap(right[n], right[0]);
flag = 1;
}
else
{
i = 0;
while(right[i]!=-1)
{
if (data[n] < data[right[i]])
{
right[n] = right[i];
right[i] = n;
flag = 1;
break;
}
i = right[i];
}
}
if (flag==0)
{
right[i] = n;
right[n] = -1;
}
i = 0;
while (right[i]!= -1)
{
cout << data[i] << " ";
i = right[i];
}
cout << data[i];
system("pause");
return 0;
}