包含了线性表的基本操作以及南航考研真题的链表操作 12-18年
#include<bits/stdc++.h>
using namespace std;
typedef struct Sqlist {
int val;
Sqlist *next;
}*ListNode;
bool InitList(ListNode &listnode)//创建一个空的线性表
{
listnode = (ListNode)malloc(sizeof(Sqlist));
if(!listnode)
{
printf("分配失败\n");
return false;
}
listnode->val = -1;
listnode->next = NULL;
return true;
}
ListNode SetupList()//给线性表赋值
{
ListNode head;
InitList(head);//创建一个空表
ListNode listnode;
listnode = head;//指向头结点
int val,count;
printf("请输入线性表元素的个数:");
scanf("%d",&count);
printf("请输入线性表的元素:");
for(int i = 0;i < count;i++)
{
scanf("%d",&val);
listnode->next = (ListNode)malloc(sizeof(Sqlist));
listnode = listnode->next;
listnode->val = val;
}
listnode->next = NULL;
return head;
}
void DisplayList(ListNode head)//输出链表的所有元素
{
ListNode listnode;
listnode = head;//指向链表头结点
while(listnode->next != NULL)
{
listnode = listnode->next;
printf("%d ",listnode->val);
}
}
bool DestroyList(ListNode &head)//销毁线性表
{
ListNode listnode;
while(head != NULL)
{
listnode = head;
head = head->next;
free(listnode);
}
head = NULL;
return true;
}
bool ClearList(ListNode &head)//置线性表为空
{
ListNode listnode,tmp;
listnode = head->next;//从头结点的下一个结点开始
tmp = listnode;
while(listnode != NULL)
{
tmp = listnode;
listnode = listnode->next;
free(tmp);
}
head->next = NULL;
return true;
}
bool ListEmpty(ListNode head)//判空
{
if(head != NULL && head->next == NULL)
return true;
else
return false;
}
int ListLength(ListNode listnode)//返回数据元素的个数
{
int length = 0;
listnode = listnode->next;//从头结点的下一个结点开始算
while(listnode != NULL)
{
length++;
listnode = listnode->next;
}
return length;
}
void ListDelete(ListNode &head,int elem)//删除
{
ListNode cur,pre;//当前节点和前驱
cur = head->next;
pre = head;
while(cur != NULL)
{
if(cur->val == elem)
{
ListNode del = cur;
pre->next = cur->next;
cur = cur->next;
free(del);
}
else
{
cur = cur->next;
pre = pre->next;
}
}
}
bool ListFind(ListNode head,int elem)//在链表中查找某个元素是否存在
{
ListNode listnode = head->next;
while(listnode != NULL)
{
if(listnode->val == elem)
return true;
else
listnode = listnode->next;
}
return false;
}
bool Sort_Ascend(ListNode &head)//采用插入排序使线性表非递减
{
//先判断是否是空表或者只有一个元素 那么一定是有序的
if(ListEmpty(head) || ListEmpty(head->next))
return true;
ListNode listnode;
listnode = head->next->next;//从第二个元素开始
head->next->next = NULL;//断掉原来的链表
while(listnode != NULL)
{
ListNode tmp = listnode;//取出一个元素
listnode = listnode->next;
ListNode pre = head;//每次判断的头结点
ListNode cur = head->next;// 需要比较的当前节点
while(cur != NULL)
{
if(cur->val > tmp->val)//小于当前节点的值则需要插入
{
tmp->next = cur;
pre->next = tmp;
break;
}
else if(cur->next == NULL)//到达链表尾部,插入尾部
{
cur->next = tmp;
tmp->next = NULL;
break;
}
else
{
cur = cur->next;
pre = pre->next;
}
}
}
return true;
}
bool Sort_Descend(ListNode &head)//采用插入排序使线性表非递增
{
//先判断是否是空表或者只有一个元素 那么一定是有序的
if(ListEmpty(head) || ListEmpty(head->next))
return true;
ListNode listnode;
listnode = head->next->next;//从第二个元素开始
head->next->next = NULL;//断掉原来的链表
while(listnode != NULL)
{
ListNode tmp = listnode;//取出一个元素
listnode = listnode->next;
ListNode pre = head;//每次判断的头结点
ListNode cur = head->next;// 需要比较的当前节点
while(cur != NULL)
{
if(cur->val < tmp->val)//大于当前节点的值则需要插入
{
tmp->next = cur;
pre->next = tmp;
break;
}
else if(cur->next == NULL)//到达链表尾部,插入尾部
{
cur->next = tmp;
tmp->next = NULL;
break;
}
else
{
cur = cur->next;
pre = pre->next;
}
}
}
return true;
}
//**************真题分界线 ******************
void MergeSort()//17年829和922真题 两个递减合并成递增
{
ListNode L1 = SetupList();
ListNode L2 = SetupList();//构建两个线性表 元素个数至少一个
Sort_Descend(L1);
Sort_Descend(L2);//降序排序
printf("链表L1:");
DisplayList(L1);
printf("\n链表L2:");
DisplayList(L2);
/*开始合并
思路1 插入排序,题目是原来是递减的,现在要求合并后递增,同时利用原节点,改代码利用的是节点L1.
思路2 直接把L2插入L1尾部 调用Sort_Ascend函数 太简单就不写了
*/
ListNode listnode = L1;
L1 = L1->next->next; //L1从第二个节点开始
listnode->next->next = NULL;//断开L1
L2 = L2->next;//L2从第一个节点开始
ListNode pre;//每次判断的前一个结点
ListNode cur;//需要比较的当前节点
while(L1 != NULL || L2 != NULL)
{
ListNode tmp;
if(L1 != NULL && L2 != NULL)//找出两个节点中值小的那一个,如果一个为空,则直接取另一个
{
if(L1->val < L2->val)
{
tmp = L1;
L1 = L1->next;
}
else{
tmp = L1;
L1 = L1->next;
}
}
else if(L1 == NULL){
tmp = L2;
L2 = L2->next;
}
else{
tmp = L1;
L1 = L1->next;
}
pre = listnode;//每次判断的前一个结点
cur = listnode->next;// 需要比较的当前节点
while(cur != NULL)
{
if(cur->val > tmp->val)//小于当前节点的值则需要插入
{
tmp->next = cur;
pre->next = tmp;
break;
}
else if(cur->val == tmp->val)//相等则去重
{
break;
}
else if(cur->next == NULL)//到达链表尾部,插入尾部
{
cur->next = tmp;
tmp->next = NULL;
break;
}
else
{
cur = cur->next;
pre = pre->next;
}
}
}
L1 = listnode;
printf("\n合并后的链表:");
DisplayList(L1);
}
void Student_Sort()// 17年829和922真题 使及格的成绩在不及格成绩的前面 要求O(n)时间复杂度
{
vector<int > student;
int n;
printf("请输入学生个数n:");
scanf("%d",&n);
printf("请输入所有学生成绩:");
for(int i = 0;i < n;i++)
{
int score;
scanf("%d",&score);
student.push_back(score);
}
//利用快排的思想 前后同时向中间扫描 然后交换
int begin = 0;
int end = n-1;
while(begin < end)
{
while(begin < n && student[begin] >= 60 )
begin++;
while(end >= 0 && student[end] < 60)
end--;
if(begin > end)
break;
int tmp = student[begin];
student[begin] = student[end];
student[end] = tmp;
begin++;
end--;
}
for(int i = 0;i < n;i++)
printf("%d ",student[i]);
}
void Delete_Duplicate()//2016年 829和922真题 删除重复节点
{
ListNode head = SetupList();
ListNode listnode = head->next;
while(listnode != NULL)
{
ListDelete(listnode,listnode->val);//调用删除函数
listnode = listnode->next;
}
DisplayList(head);
}
void SimpleSort()//15年829和922真题 简单选择排序
{
ListNode head = SetupList();
ListNode listnode = head->next;
while(listnode != NULL)
{
ListNode min = listnode; //假设当前值是最小值
ListNode cur = listnode->next;
while(cur != NULL)
{
if(min->val > cur->val)
min = cur;
cur = cur->next;
}//找到最小值的节点
int tmp = listnode->val;
listnode->val = min->val;
min->val = tmp;//交换节点的值
listnode = listnode->next;
}
DisplayList(head);
}
void AdjustList()//14年829和922真题 偶数次序的节点倒序插入后边
{
int flag = 1;//奇偶节点的标志
ListNode head = SetupList();
ListNode pre = head;//当前节点的前驱
ListNode cur = head->next;//当前节点
ListNode end = head; //最后一个节点an
ListNode post = NULL;// end节点的后继
while(end->next != NULL) { end = end->next; } //找到最后一个节点
while(cur != end)
{
if(flag == 2)//偶数节点
{
ListNode tmp = cur;
pre->next = cur->next;
cur = cur->next;//去掉偶数节点
end->next = tmp;
tmp->next = post;
post = tmp;//插入an节点的后面
flag = 1; //下一个是奇数节点
}
else
{
flag = 2; //下一个是偶数节点
cur = cur->next;
pre = pre->next;
}
}
DisplayList(head);
}
void IntersectionList()//13年829和922真题 求AB链表的交集 并排序
{
ListNode A = SetupList();
ListNode B = SetupList();
Sort_Ascend(A);
Sort_Ascend(B); //A B递增有序
printf("A链表:");
DisplayList(A);
printf("\nB链表:");
DisplayList(B);
/*
开始求交集 注意:A里面可能有重复的元素,还需要去重
思路1 利用Delete_Duplicate函数,先对A去重,然后利用ListFind函数
判断A里面的元素是否在B表,不在则删除,最后对A表调用Sort_Descend函数排序
因为考试题只有一个,所以我们采用思路2
思路2 通过ListFind函数分别查找A B表,找出交集元素,以及删除A中重复元素 ,
中间采用插入排序的思想使A表倒序
*/
ListNode pre = A;
ListNode cur = A->next;
while(cur != NULL)
{
if(ListFind(B,cur->val) && !ListFind(cur,cur->val) ){ pre = pre->next; cur = cur->next; } //B中有该节点 A中没重复的
else if(ListFind(B,cur->val) && ListFind(cur,cur->val) )//B中有 A中也有 删除该节点
{
ListNode tmp = cur;
pre->next = cur->next;
cur = cur->next;
free(tmp);
}
else//B中没有
{
ListNode tmp = cur;
pre->next = cur->next;
cur = cur->next;
free(tmp);
}
}
Sort_Descend(A);
printf("\nAB链表的交集降序排列:");
DisplayList(A);
}
int OperateList()//2018年829和922真题 调整链表使负数节点在正数节点后面且返回第一个负数节点位置
{
/*
思想: 找到负数节点 插入到尾节点 ,同时第一次就找到了第一个负数节点
或者最后一个正数节点的位置,如果前面有一个节点插入到尾部,则位置减一
*/
ListNode head = SetupList();//建立链表
int index = 1;
ListNode end = head->next; //尾节点 用于插入
ListNode post = NULL; //尾节点的后继
ListNode pre = head; //当前节点的前驱
ListNode cur = head->next; //当前节点
while(end->next != NULL) //找到尾节点 同时找到节点位置
{
end = end->next;
index++;
}
while(cur != end) //当前节点未到达尾节点
{
if(cur->val < 0)
{
ListNode tmp = cur;
pre->next = cur->next;
cur = cur->next; // 断开负节点
tmp->next = post;
end->next = tmp;
post = end->next; //插入尾节点
index--; //位置要减少一 因为少了一个节点
}
else
{
cur = cur->next;
pre = pre->next;
}
}
if(end->val >= 0) //最好特别判断一下尾节点 如果值大于零 说明位置要加一
index++;
//DisplayList(head); 输出结果 没问题
return index;
}
void Sort_Negative() //2012年922真题 O(n)时间内使负数在正数前面
{
/*
算法思想:思路和18年思路基本一致
*/
ListNode head = SetupList();//建立链表
ListNode end = head->next; //尾节点 用于插入
ListNode post = NULL; //尾节点的后继
ListNode pre = head; //当前节点的前驱
ListNode cur = head->next; //当前节点
while(end->next != NULL) //找到尾节点 同时找到节点位置
{
end = end->next;
}
while(cur != end) //当前节点未到达尾节点
{
if(cur->val > 0)
{
ListNode tmp = cur;
pre->next = cur->next;
cur = cur->next; // 断开负节点
tmp->next = post;
end->next = tmp;
post = end->next; //插入尾节点
}
else
{
cur = cur->next;
pre = pre->next;
}
}
DisplayList(head);
}
int main()
{
ListNode listnode;
//listnode = SetupList();
//DestroyList(listnode);
//ClearList(listnode);
//cout<<listnode->val;
//ListLength(listnode);
//Sort(listnode);
//DisplayList(listnode);
//MergeSort();
//Student_Sort();
//Delete_Duplicate();
//SimpleSort();
//AdjustList();
//IntersectionList();
//printf("%d",OperateList() );
//Sort_Negative();
return 0;
}