1、创建
2、显示
3、查找(显示比较次数)
4、插入
5、删除(显示比较次数)
6、将链接存储线性表逆置,即最后一个结点变成第1个结点,原来倒数第2个结点变成第2个结点,如此等等。
7、生成有序的两个单链表A和B(链表的数据和个数自定),其首结点指针分别为a和b,要求将两个单链表合并为一个有序的单链表C,其首结点指针为c,并且合并后的单链表的数据不重复。
8、将一个首结点指针为a的单链表A分解成两个单链表A和B,其首结点指针分别为a和b,使得链表A中含有原链表A中序号为奇数的元素,而链表B中含有原链表A中序号为偶数的元素,且保持原来的相对顺序。
单链表操作菜单如下图所示:

以下已给出:
公用的等待函数
void wait()
{
cout << "\n\n请按任意键继续" << flush;
getch();
}
屏幕提示后,从键盘输入线性表长度和随机数种子,生成以DLList为头指针的指定长度的线性表
void init(Node *DLList)
{
int length;
Node *p,*q;
while (1)
{
cout << "输入元素个数(0-" << 10000 << "):" << flush;
cin >> length;
if (length >= 0 && length <= 10000)
break;
cout << endl;
}
int i;
while (1)
{
cout << "输入随机数种子(0-32767):" << flush;
cin >> i;
if (i >= 0 && i <= 32767)
break;
cout << endl;
}
//从线性表中删除并释放原有的结点,使其成为空表
p=DLList;
while (p->next!=NULL)
{
q=p->next;
p->next=q->next;
free(q);
}
srand(i); //指定随机数种子,相同的种子将产生相同的数据序列
rand();
//向线性表插入length个新结点
for (int j=1;j<=length;j++)
{
p=new Node;
p->next=DLList->next;
DLList->next=p;
p->elem=rand() % 10000;
}
}
一些个人感想:
我认为链表合并有些瑕疵,写的并不好;选择法排序那里不是很能理解透彻,个人认为可以偷懒,利用插入函数把一个个排好的数据插入一个新链表,在把旧链表等于新链表,但这样又不是很符合选择排序的思想。
这4行关键代码理解了蛮久的
temp=min->next;
min->next=temp->next;//将本循环的最小值从链表删除
temp->next=p->next;
p->next=temp;//将本循环的最小值插入链表
全部代码如下:
#include <iostream>
#include <iomanip>
#include <conio.h>
#include <stdio.h>
#include <process.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
using namespace std;
//定义结点类型
struct Node
{
int elem;
Node *next;
};
Node Head; //头结点
Node *DLList; //头指针
void init(Node *DLList);
void display(Node *DLList);
void insert(Node *DLList);
void search(Node *DLList);
void del(Node *DLList);
void wait();
void selectionSort(Node *DLList);
void listReverse(Node *DLList);
void listMerge(Node *DLList);
void listSplit(Node *DLList);
bool empty(Node *DLList);
void elemInsert(Node *DLList,int data);
int length(Node *DLList);
int main()
{
char choice;
DLList=&Head; //使头指针指向头结点
Head.next=NULL;
while (1)
{
system("cls");
cout << "\n\n\n\n";
cout << "\t\t 单链表操作 \n";
cout << "\t\t======================================";
cout << "\n\n";
cout << "\t\t 1:初始化 \n";
cout << "\t\t 2:显示 \n";
cout << "\t\t 3:单个插入 \n";
cout << "\t\t 4:查找 \n";
cout << "\t\t 5:删除 \n";
cout << "\t\t 6:选择法排序 \n";
cout << "\t\t 7:逆置链表 \n";
cout << "\t\t 8:合并两链表 \n";
cout << "\t\t 9:拆分链表 \n";
cout << "\t\t 0:退出 \n";
cout << "\n";
cout << "\t\t请选择:" << flush;
choice = getch();
system("cls");
switch(choice)
{
case '1':
init(DLList);
wait();
break;
case '2':
display(DLList);
wait();
break;
case '3':
insert(DLList);
wait();
break;
case '4':
search(DLList);
wait();
break;
case '5':
del(DLList);
wait();
break;
case '6':
selectionSort(DLList);
wait();
break;
case '7':
listReverse(DLList);
wait();
break;
case '8':
listMerge(DLList);
wait();
break;
case '9':
listSplit(DLList);
wait();
break;
case '0':
exit(0);
}
}
}
//公用的等待函数
void wait()
{
cout << "\n\n请按任意键继续" << flush;
getch();
}
//屏幕提示后,从键盘输入线性表长度和随机数种子,生成以DLList为头指针的指定长度的线性表
void init(Node *DLList)
{
int length;
Node *p,*q;
while (1)
{
cout << "输入元素个数(0-" << 10000 << "):" << flush;
cin >> length;
if (length >= 0 && length <= 10000)
break;
cout << endl;
}
int i;
while (1)
{
cout << "输入随机数种子(0-32767):" << flush;
cin >> i;
if (i >= 0 && i <= 32767)
break;
cout << endl;
}
//从线性表中删除并释放原有的结点,使其成为空表
p=DLList;
while (p->next!=NULL)
{
q=p->next;
p->next=q->next;
free(q);
}
srand(i); //指定随机数种子,相同的种子将产生相同的数据序列
rand();
//向线性表插入length个新结点
for (int j=1;j<=length;j++)
{
p=new Node;
p->next=DLList->next;
DLList->next=p;
p->elem=rand() % 10000;
}
}
//在屏幕上依次显示以DLList为头指针的线性表中的全部元素和元素个数
//格式应便于观察
//如果需要指定输出的宽度,可以使用 cout << setw(W) << X ,其中 X 是输出的数值,W 是占据的列数
void display(Node *DLList)
{
if(empty(DLList))
return;
Node *p=DLList->next;
int i=1;//控制换行
while(p!=NULL)
{
cout <<setiosflags(ios::left)/*左对齐*/<< setw(15) << p->elem;
if(i%10==0) printf("\n");
i++;
p=p->next;
}
printf("\n此表中共有%d个元素!\n",length(DLList));
}
//屏幕提示后,从键盘输入一个元素值,然后把这个新元素插到以DLList为头指针的线性表的末尾
void insert(Node *DLList)
{
int i;
Node *p=DLList,*temp;
while(p->next!=NULL)
p=p->next;
temp=new Node;
printf("请输入插入元素的值:");
scanf("%d",&temp->elem);//数据域
temp->next=NULL;//指针域
p->next=temp;
printf("插入成功!\n");
}
//屏幕提示后,从键盘输入一个元素值,在以DLList为头指针的线性表中搜索这个元素
void search(Node *DLList)
{
if(empty(DLList))
return;
Node *p;
p=DLList->next;
int elem,count=0;
printf("请输入查找元素值:");
scanf("%d",&elem);
while(p!=NULL)
{
count++;
if(p->elem==elem)
{
printf("该元素在链表第%d位,共比较%d次\n\n",count,count);
display(DLList);
return;
}
p=p->next;
}
printf("链表无此元素!共比较%d次\n",count);
}
//屏幕提示后,从键盘输入一个元素值,在以DLList为头指针的线性表中删除这个元素
//屏幕显示删除成功与否的信息
void del(Node *DLList)
{
Node *p,*s;
if(empty(DLList))
return;
int delelem,count;
printf("请输入要删除元素值:");
scanf("%d",&delelem);
while(p->next!=NULL)
{
count++;//比较次数
if(delelem==p->next->elem)
{
s=p->next;//指向删除元素
p->next=p->next->next;//覆盖
printf("删除成功!,共比较%d次\n",count);
free(s);//释放内存
return;
}
p=p->next;
}
printf("链表无此元素!共比较%d次\n",count);
}
//选择法排序
void selectionSort(Node *DLList)
{
if(empty(DLList))
return;
Node *p,*q,*min,*temp;
p=DLList;
while(p->next!=NULL)
{
q=p->next;
min=p;
while(q->next!=NULL)
{
if(q->next->elem < min->next->elem)
min=q;
q=q->next;
}
if(min!=p)
{
temp=min->next;
min->next=temp->next;//将本循环的最小值从链表删除
temp->next=p->next;
p->next=temp;//将本循环的最小值插入链表
}
p=p->next;
}
printf("排序完成!");
}
//应用题
//6、将链接存储线性表逆置,即最后一个结点变成第1个结点,原来倒数第2个结点变成第2个结点,如此等等。
void listReverse(Node *DLList)
{
if(empty(DLList))
return;
printf("逆置前:\n");
display(DLList);
Node *p,*q,*s;
p=DLList->next;//p指向第一个元素
q=p->next;//q指向第二个元素
p->next=NULL;//p指针域为NULL,即链表尾部
while(q)//判断
{
s=q->next;//未逆置部分
q->next=p;//逆置
p=q;//p保存
q=s;//提取下一个
}
DLList->next=p;
printf("\n逆置后:\n");
display(DLList);
}
/*7、生成有序的两个单链表A和B(链表的数据和个数自定),其首结点指针分别为a和b,要求将两
个单链表合并为一个有序的单链表C,其首结点指针为c,并且合并后的单链表的数据不重复。
*/
void listMerge(Node *DLList)
{
if(empty(DLList))
return;
Node *DLList2;//链表2
Node *DLList3;//最终表
Node head2,head3;//头节点
head2.next=NULL;head3.next=NULL;
DLList2=&head2;
DLList3=&head3;
Node *p,*p2,*p3;
printf("请设置顺序表2:\n");
init(DLList2);
selectionSort(DLList);
selectionSort(DLList2);
system("cls");
p=DLList->next;
p2=DLList2->next;
p3=DLList3;
//求交集并排序
while(p!=NULL&&p2!=NULL)
{
if(p->elem==p2->elem)
{
elemInsert(DLList3,p->elem);
p=p->next;
p2=p2->next;
}
else if(p->elem<p2->elem)
{
elemInsert(DLList3,p->elem);
p=p->next;
}
else
{
elemInsert(DLList3,p2->elem);
p2=p2->next;
}
}
//找到DLList的尾指针位置
while(p3->next!=NULL)
p3=p3->next;
//尾部处理
if(p==NULL)
p3->next=p2;
else if(p2==NULL)
p3->next=p;
printf("排序成功!\n");
printf("表一:\n");
display(DLList);
printf("表二:\n");
display(DLList2);
DLList->next=DLList3->next;
free(DLList3);//释放空间
free(DLList2);//释放空间
printf("新表:\n");
display(DLList);
}
//8、将一个首结点指针为a的单链表A分解成两个单链表A和B,其首结点指针分别为a和b,使得链表A中含有原链表A中序号为奇数的元素,而链表B中含有原链表A中序号为偶数的元素,且保持原来的相对顺序。
void listSplit(Node *DLList)
{
if(empty(DLList))
return;
Node *DLList_odd;//奇数链表
Node *DLList_even;//偶数链表
Node head_odd,head_even;//头结点
head_odd.next=NULL;
head_even.next=NULL;
DLList_odd=&head_odd;
DLList_even=&head_even;
Node *p=DLList->next;
int serial=1;//序号
//判断奇偶
while(p)
{
if(serial%2==0)
elemInsert(DLList_even,p->elem);
else
elemInsert(DLList_odd,p->elem);
serial++;
p=p->next;
}
printf("奇数:\n");
display(DLList_odd);
printf("\n");
printf("偶数:\n");
display(DLList_even);
free(DLList_odd);
free(DLList_even);
}
//判断链表是否为空,true为空
bool empty(Node *DLList)
{
Node *p;
p=DLList;
if(p->next==NULL)
{
printf("链表为空,请初始化!\n");
return true;
}
return false;
}
//输出链表长度
int length(Node *DLList)
{
if(empty(DLList))
return 0;
Node *p=DLList;
int length=0;
while(p->next!=NULL)
{
length++;
p=p->next;
}
return length;
}
//插入指定元素
void elemInsert(Node *DLList,int data)
{
int i;
Node *p=DLList,*temp;
while(p->next!=NULL)
p=p->next;
temp=new Node;
temp->elem=data;
temp->next=NULL;//指针域
p->next=temp;
}