目前实现的所有操作如下图所示:
学数据结构半个多月了,下面是整合的对单链表组的操作,测试了一下数据,应该没问题。
以下是代码:
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#define MAXNUM 10
int cnt = 0;
typedef struct node {
int data;
struct node* next;
}Node, *LinkList;
//链表的初始化操作
void Init(LinkList *L) {
*L = (LinkList)malloc(sizeof(Node));
(*L)->data = 0;
(*L)->next = 0;
}
void InitClear(LinkList *L) {
(*L)->next = NULL;
}
//进行当前链表,链表组的打印
void PrintCurrList(LinkList*L) {
LinkList p = (*L)->next;
printf("Head->");
if (!p)
printf("NULL");
while (p) {
printf("%d", p->data);
if (p->next)
printf("->");
p = p->next;
}
printf("\n");
}
int PrintAllList(LinkList*L) {
int Index = 0;
LinkList*p = L;
int tag, IsDisplay = 0;
while (Index < 10) {
if (p[Index]) {
printf("L%d:", Index);
PrintCurrList(p + Index);
IsDisplay = 1;
}
Index++;
}
if (IsDisplay) {
printf("请输入当前想操控的链表:\n");
scanf("%d", &tag);
while (!*(L + tag)) {
printf("输入有误,请再次输入: ");
scanf("%d", &tag);
}
return tag;
}
else {
printf("当前列表空荡荡,请创建链表\n");
return 0;
}
}
void CreateList(LinkList*L) {
*L = (LinkList)malloc(sizeof(Node));
(*L)->data = 0;
LinkList tail = *L, p;
int j = 0, temp, n;
printf("请输入结点数目:");
scanf("%d", &n);
while (j++ < n) {
p = (LinkList)malloc(sizeof(Node));
scanf("%d", &temp);
p->data = temp;
tail->next = p;
tail = p;
}
tail->next = 0;
}
void CreateHead(LinkList*L, int*a, int len) {
*L = (LinkList)malloc(sizeof(Node));
int i = 0;
LinkList p;
(*L)->data = 0;
(*L)->next = NULL;
while (i < len) {
p = (LinkList)malloc(sizeof(Node));
p->data = a[i++];
p->next = (*L)->next;
(*L)->next = p;
}
}
int getLen(LinkList *L) {
LinkList p = (*L)->next;
int cnt = 0;
while (p) {
p = p->next;
cnt++;
}
return cnt;
}
int defaultL(LinkList*L) {
cnt = 0;
while (*L) {
L++;
cnt++;
}
if (cnt > 9) cnt = 9;
return cnt;
}
LinkList getNode(LinkList*L, int i) {
LinkList p = (*L);
int j;
for (j = 0; p&&j < i; j++) {
p = p->next;
}
if (!p || j > i)
return 0;//相当于return为空
return p;
}
void swapNode(LinkList*L, int a, int b) {
int len = getLen(L);
//此时在赋值后,L可以当做一个地址在之后的函数中操作
if (b > len || b<1 || a>len || a < 1||a==b) {
printf("输入的结点有误!\n");
}
else {
if (abs(a - b) == 1) {
LinkList p;
if (a<b)
p = getNode(L, a - 1);
if (b < a) p = getNode(L, b - 1);
LinkList anode, bnode;
anode = p->next;
bnode = anode->next;
anode->next = bnode->next;
bnode->next = anode;
p->next = bnode;
}
else {
LinkList apre, anode, anext, bpre, bnode, bnext;
apre = getNode(L, a - 1);
anode = apre->next;
anext = apre->next->next;
bpre = getNode(L, b - 1);
bnode = bpre->next;
bnext = bpre->next->next;
bnode->next = anext;
apre->next = bnode;
bpre->next = anode;
anode->next = bnext;
bnode->next = anext;
}
}
}
void Insertnode(LinkList *L, int i, int data) {
int j = 1;
int len = getLen(L) + 1;
LinkList p = *L, q;
if (!p || i>len || i<1) return;
for (j; j < i&&p; j++) {
p = p->next;
}
q = (LinkList)malloc(sizeof(Node));
q->data = data;
q->next = p->next;
p->next = q;
}
void deleteNode(LinkList*L, int data) {
LinkList p = (*L)->next, q;
while (p->next) {
if (p->next->data == data) break;
p = p->next;
}
if (!(p->next)) {
printf("你所查找的数据不存在\n");
return;
}
else {
q = p->next;
p->next = q->next;
free(q);
}
}
void ClearList(LinkList*L) {
LinkList p = *L, q;
while (p) {
q = p->next;//先进行预存,因为删除后就无法进行访问了
free(p);
p = q;
}
*L = 0;
}
LinkList getmidnode(LinkList*L) {
LinkList s, p = (*L)->next;
s = p;
while (p) {
//在p改变之前先进性改变
if (!(p->next)) break;
p = p->next->next;
s = s->next;
}
return s;
}
//在排序中要保留结点的前驱部分,前驱部分不会随着交换而改变
void BubbleSort(LinkList*L) {
LinkList end, p, temp, p1;
p = *L;
for (end = 0; end != *L; end = temp) {
//for循环中先执行条件语句,然后执行之后的代码,最后再执行赋值语句
for (temp = p = *L; p->next->next != end; p = p->next) {
//最开始给了end空值,所以开始要循环到末尾,要从被比较结点前面的一个结点开始操作,所操作的最大限值在p->next->next
if (p->next->data > p->next->next->data) {
//p1 = p->next;
//p1->next = p1->next->next;//这一步就相当于删除了p1后面的结点,不能在进行交换操作了
//p1->next->next = p1;
//p->next = p1->next;
p1 = p->next->next;//要先保存住排在后面的结点
p->next->next = p1->next;
p1->next = p->next;
p->next = p1;
temp = p->next->next;
}
}
}
}
void SelectSort(LinkList*L) {
LinkList start, p, temp, p2, temp1;
start = (*L)->next;
int cnt = 1, cnt1;
for (p = start; p; p = temp->next) {
cnt1 = cnt;
for (p2 = temp = p; p2; p2 = p2->next, cnt1++) {
//这些指针只是位置的指标,实际操作的链表是一体的
if (p->data > p2->data) {
temp1 = p;//提前预留交换后的状态
swapNode(L, cnt, cnt1);
p = temp = getNode(L, cnt);
p2 = temp1;
}
}
cnt++;
}
}
void selectSort2(LinkList *L) {
//相当于新建了一个链表,把原链表的结点按最小值依次拆分放到新链表中
LinkList start, tail, min, minpre, p;
start = 0;
while (*L) {
for (p = *L, min = *L; p->next; p = p->next) {
//头结点和min要默认定义在最开始的节点上
if (p->next->data < min->data) { //找到一个比当前结点更小的结点
minpre = p;//保存上最小结点前面的结点,不会随着链表的变动而变动,以便于以后的操作
min = p->next;
}
}
if (!start) {
start = min;
tail = min;
}
/*
//教训:此时要加else,如果是if语句的话就承接了上面的if语句,最终结果为整个链表都为头结点的值
if(start) {
tail->next = min;
tail = min;
}
*/
else {
tail->next = min;
tail = min;
}
//将最小的那个结点从原链表中移除掉
if (min == *L) {
*L = (*L)->next;
}
else {
minpre->next = min->next;
}
//free(min); //不要把原结点的空间释放掉
}
tail->next = 0;
*L = start;//为原链表重新赋值
}
void Insertsort(LinkList*L) {
LinkList p, start, min, minpre, q;
start = (*L)->next;//插入要从后面的数开始
(*L)->next = 0;//把原链表换为空链表,然后再插入
//整个插入过程是把start插入到*L,然后根据start指针把start内的成员逐个插入到*L中
while (start) {
for (p = *L, q = start; p&&start->data > p->data; minpre = p, p = p->next);
//在此获得start应插入到*L的前结点
//q是预留的start空间
start = start->next;//注意:这里start先进行,因为下面q的变化会联动start,先在此预留空间
if (p == *L) {//插在头结点前面时
*L = q;
q->next = p;
}
else {
//其余情况,*L中有小于start的结点,则插到*L中
minpre->next = q;
q->next = p;
}
}
}
void InsertOrdered(LinkList*L, int data) {
LinkList q = *L, pre;
LinkList p = (LinkList)malloc(sizeof(Node));
p->data = data;
if (!(*L)) {//若*L是空链表,则为其创建头结点
*L = p;
p->next = 0;
}
else {
//while (q->data < p->data&&q) {
//教训:一定要把q放到前面,当q为空时,q->data已经不能访问,先判断q==NULL,可免去后续的判断
while (q&&q->data < p->data) {
pre = q;
q = q->next;
}
if (q == *L) {
*L = p;
p->next = q;
}
else {
p->next = pre->next;
pre->next = p;
}
}
}
void PrintList(LinkList*L) {
int Index = 0;
LinkList*p = L;
int IsDisplay = 0;
while (Index < 10) {
if (p[Index]) {
printf("L%d:", Index);
PrintCurrList(p + Index);
IsDisplay = 1;
}
Index++;
}
}
void Combined(LinkList*L, LinkList*b) {
if (!(*b)) return;
else {
LinkList p = *L, pre;
while (p) {
pre = p;
p = p->next;
}
LinkList q = (*b)->next;
pre->next = q;
free(*b);
*b = 0;
//ClearList(b);//不要清除整个链表,只清楚头结点即可
}
}
void ReverseList(LinkList*L) {
LinkList p = (*L)->next, q = 0, temp, p1 = *L;
while (p) {
temp = p->next;
p->next = q;
q = p;
p = temp;
}
p1->next = q;
//把预留的头结点接到q上,这样实现了出来头结点以外其他结点的倒置
*L = p1;
}
void ClearAllList(LinkList *L) {
for (int i = 0; i < MAXNUM; i++)
ClearList(L + i);
}
void Menu() {
printf("1:创建链表(空链表)\n2:创建链表(头插法,数组创建)\n3:创建链表(尾插法,自己赋值)\n4:显示与改变当前链表\n");
printf("5:当前链表长度\n6:获取第i个结点的数据\n7:交换两结点\n8:插入结点\n9:删除结点\n10:获取中间结点数据\n");
printf("11:排序链表(冒泡排序)\n12:排序链表(插入排序)\n13:排序链表(选择排序)\n14:插入有序结点\n");
printf("15:合并链表\n16:倒置链表\n17:初始化为空链表\n18:删除该链表\n19:清空数据并重新显示菜单\n20:退出该程序\n");
}
int main() {
static int LinkTag, temp;
//static,每次调用时为上次调用的值,其存储空间一旦声明就不会释放
int a[] = { 3,23,34,43,151,325,32 };
int len = sizeof(a) / sizeof(int);
LinkList L[MAXNUM] = { 0 };
LinkList tempList;
int choice, num1, num2;
Menu();
while (1) {
printf("--------------------------------------\n");
printf("请输入您的操作:");
scanf("%d", &choice);
switch (choice)
{
case 1:
LinkTag = defaultL(L);
Init(L + LinkTag);
PrintCurrList(L + LinkTag);
break;
case 2:
LinkTag = defaultL(L);
CreateHead(L + LinkTag, a, len);
PrintCurrList(L + LinkTag);
break;
case 3:
LinkTag = defaultL(L);
CreateList(L + LinkTag);
PrintCurrList(L + LinkTag);
break;
case 4:
LinkTag = PrintAllList(L);
break;
case 5:
printf("当前链表长度为%02d\n", getLen(L + LinkTag));
break;
case 6:
printf("输入第i个结点:");
scanf("%d", &temp);
tempList = getNode(L + LinkTag, temp);
if (!tempList)
printf("该节点不存在\n");
else
printf("L%d的第%d个值为:%d\n", LinkTag, temp, tempList->data);
break;
case 7:
printf("请输入要交换的两个结点:");
scanf("%d %d", &num1, &num2);
swapNode(&L[LinkTag], num1, num2);
PrintCurrList(L + LinkTag);
break;
case 8:
printf("输入要插入的结点 和 数字:");
scanf("%d %d", &num1, &num2);
Insertnode(L + LinkTag, num1, num2);
PrintCurrList(L + LinkTag);
break;
case 9:
printf("输入你要删除的数据:");
scanf("%d", &num1);
deleteNode(L + LinkTag, num1);
PrintCurrList(L + LinkTag);
break;
case 10:
tempList = 0;
tempList = getmidnode(L + LinkTag);
printf("当前链表的中间结点数据为%d\n", tempList->data);
break;
case 11:
BubbleSort(L + LinkTag);
PrintCurrList(L + LinkTag);
break;
case 12:
Insertsort(L + LinkTag);
PrintCurrList(L + LinkTag);
break;
case 13:
selectSort2(L + LinkTag);
PrintCurrList(L + LinkTag);
break;
case 14:
printf("输入你要插入的数据:");
scanf("%d", &num1);
InsertOrdered(L + LinkTag, num1);
PrintCurrList(L + LinkTag);
break;
case 15:
PrintList(L);
printf("当前链表为L%d,请输入想要合并的链表:", LinkTag);
scanf("%d", &num1);
Combined(L + LinkTag, L + num1);
PrintCurrList(L + LinkTag);
break;
case 16:
ReverseList(L + LinkTag);
PrintCurrList(L + LinkTag);
break;
case 17:
InitClear(L + LinkTag);
PrintCurrList(L + LinkTag);
break;
case 18:
ClearList(L + LinkTag);
printf("删除该链表之后,还剩下:\n");
PrintAllList(L);
break;
case 19:
system("cls");
ClearAllList(L);
Menu();
break;
case 20:
exit(0);
break;
default:
break;
}
}
return 0;
}