创建list.h头文件
#pragma once
//头结点:开头标识,类似旗帜,不存放数据,不参与运算
//数据结点:存放数据
typedef struct Node
{
int data;
struct Node *next;
}Node,*pList;
//初始化
void InitSeqList(pList plist);
//头插
bool Insert_head(pList plist,int val);
//尾插
bool Insert_tail(pList plist,int val);
//在plist中查找关键字Key,找到后返回地址,失败返回-1
Node *Search(pList plist,int key);
//判空
bool IsEmpty(pList plist);
//删除第一个key值
bool DeleteVal(pList plist,int key);
//获取数据长度
int GetLength(pList plist);
//显示
void Show(pList plist);
//清空数据
void Clear(pList plist);
//销毁动态内存
void Destroy(pList plist);
创建list.cpp文件
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
#include"list.h"
/*
注意事项:
1.找后一个节点是p=p->next;不能写成p++
*/
//判空
static void DeterPointNull(pList plist)
{
assert(plist!=NULL);
if(plist==NULL)
{
exit(0);
}
}
//初始化
void InitSeqList(pList plist)
{
DeterPointNull(plist);
plist->next=NULL;
}
//头插
bool Insert_head(pList plist,int val)
{
DeterPointNull(plist);
//程序出错,由于Node定义的是局部变量,使用后便销毁,无法传递回去
/*Node node;
node.data=val;
node.next=plist->next;
plist->next=&node;*/
Node *p=(Node *)malloc(sizeof(Node));
p->data=val;
p->next=plist->next;
plist->next=p;
return true;
}
//尾插
bool Insert_tail(pList plist,int val)
{
DeterPointNull(plist);
//创建新节点
Node *p=(Node *)malloc(sizeof(Node));
//将值存放到新节点
p->data=val;
//找尾结点
Node *q;
for(q=plist;q->next!=NULL;q=q->next);
//将新节点插入到q后面
p->next=q->next;// 相当于p->next=NULL;
q->next=p;
return true;
}
//在plist中查找关键字Key,找到后返回地址,失败返回空指针
Node *Search(pList plist,int key)
{
DeterPointNull(plist);
for(Node *p=plist->next;p!=NULL;p=p->next)
{
if(p->data==key)
{
return p;
}
}
return NULL;
}
//判空
bool IsEmpty(pList plist)
{
DeterPointNull(plist);
return plist->next==NULL;
}
//删除plist中的第一个key
bool DeleteVal(pList plist,int key)
{
DeterPointNull(plist);
Node *q;
for(Node *p=plist->next;p!=NULL;)
{
q=p->next;
if(p->data==key)
{
plist->next=p->next;
free(p);
return true;
}
if(q->data==key)
{
p->next=q->next;
free(q);
return true;
}
}
return false;
}
//获取数据长度
int GetLength(pList plist)
{
DeterPointNull(plist);
int count=0;
for(Node *p=plist->next;p!=NULL;p=p->next)
{
count++;
}
return count;
}
//显示
void Show(pList plist)
{
DeterPointNull(plist);
for(Node *p=plist;p->next!=NULL;p=p->next)
{
printf("%-5d",p->next->data);
}
printf("\n");
}
//清空数据
void Clear(pList plist)
{
DeterPointNull(plist);
plist->next=NULL;
}
//销毁动态内存
//总是删除第一个数据结点
void Destroy(pList plist)
{
DeterPointNull(plist);
Node *p;
while (plist->next!=NULL)//还有第一个数据结点
{
p=plist->next;//p指向第一个数据结点
plist->next=p->next;//将p从链表中剔除
free(p);
}
}
/*
//销毁动态内存
void Destroy(pList plist)
{
DeterPointNull(plist);
Node *p=plist->next;//指向需要删除的结点
Node *q;//p的下一个节点,不能直接赋值=p->next
while (p=plist->next!=NULL)
{
q=p->next;
free(p);
p=q;
}
plist->next=NULL;
}
*/
其他功能:
1.已知递增有序的单链表A,B,C分别存储了一个集合,设计算法实现A:AU(BnC),并使求解结构A仍保持递增。
要求算法的时间复杂度为O(|A|+|B|+|C|)。其中,|A|为集合A的元素个数
void Calculate(pList plistA,pList plistB,pList plistC)
{
Node *p1=plistA;
Node *p2=plistB->next;
Node *p3=plistC->next;
while (p1->next!=NULL && p2!=NULL && p3!=NULL)
{
if(p2->data==p3->data)
{
if(p1->next->data<p2->data)
{
if(p1->next->next==NULL)
{
Insert_tail(plistA,p2->data);
}
p1=p1->next;
}
else if(p1->next->data==p2->data)
{
p2=p2->next;
p3=p3->next;
}
else
{
Node *q=(Node *)malloc(sizeof(Node));
q->data=p2->data;
q->next=p1->next;
p1->next=q;
}
}
else if(p2->data<p3->data)
{
p2=p2->next;
}
else if(p2->data>p3->data)
{
p3=p3->next;
}
}
}
int main()
{
Node headA;
InitSeqList(&headA);
Node headB;
InitSeqList(&headB);
Node headC;
InitSeqList(&headC);
Insert_tail(&headA,2);
Insert_tail(&headA,3);
Insert_tail(&headA,7);
Insert_tail(&headA,8);
Insert_tail(&headA,9);
Insert_tail(&headB,1);
Insert_tail(&headB,5);
Insert_tail(&headB,6);
Insert_tail(&headB,8);
Insert_tail(&headB,10);
Insert_tail(&headC,1);
Insert_tail(&headC,3);
Insert_tail(&headC,6);
Insert_tail(&headC,9);
Insert_tail(&headC,10);
Show(&headA);
Show(&headB);
Show(&headC);
Calculate(&headA,&headB,&headC);
Show(&headA);
return 0;
}
2.将链表逆置
//算法1:利用栈实现(利用数组模拟栈)//时间复杂度:O(n) 空间复杂度:O(n)
void Reverse1(pList plist)
{
int len=GetLength(plist);
int *arr=(int *)malloc (len*sizeof(int));
assert(arr!=NULL);
int i=0;//arr的下标
//从头到尾遍历plist,将数据全部存放到arr中
for(Node *p=plist->next;p!=NULL;p=p->next)
{
arr[i++]=p->data;
}
//金属组中的数据从后往前,再赋值到链表中
i=len-1;//最后一个元素的下标
for(Node *p=plist->next;p!=NULL;p=p->next)
{
p->data=arr[i--];
}
free(arr);
}
//算法2:利用头插和尾插相反的算法 //O(n) O(1)
void Reverse(pList plist)
{
Node *p=plist->next;
Node *q;
plist->next=NULL;
while(p!=NULL)
{
q=p->next;
//将p头插到plist中
p->next=plist->next;
plist->next=p;
p=q;
}
}
3.给定单链表,检测是否有环,并返回相遇结点
//查找相遇结点
static pList IsCircle(pList plist)
{
Node *p=plist;//快指针
Node *q=plist;//慢指针
while(q!=NULL)//q为快指针,所以即使为NULL,也是q先为NULL,所以不对p进行判断
{
p=p->next;
q=q->next;
if(q==NULL)
{
return NULL;
}
q=q->next;
if(p==q)
{
return p;//有环,返回快慢指针的相遇结点
}
}
return NULL;
}
//判断是否有环
pList IsCircleList(pList plist)
{
DeterPointNull(plist);
//pNode是快慢指针相遇的结点,不一定是入环的第一个节点
pList pNode =IsCircle(plist);//找到相遇结点
if(pNode==NULL)//无环
{
return NULL;
}
//求入环的第一个节点
Node *p=pNode;//相遇结点
Node *q=plist;//头结点
while(p!=q)//有环,不为NULL
{
p=p->next;
q=q->next;
}
return p;//肯定为入环的第一个节点
}
4.给定两个单链表(head1,head2),检测两个链表是否有交点,如果有,返回第一个交点
思路1:通过两个指针,直接跑到最后一个结点,判断两个结点的地址是否相等,但是不返回第一个交点
2思路:求得两个链表的长度,求差值,指向长的链表的指针先跑差值的节点数,两个指针再同时往后跑,每跑一个节点,判断其地址是否相等,则直接返回其中一个指针,这就是相交的第一个节点
pList TwoListIntersec1(pList plistA,pList plistB)
{
DeterPointNull(plistA);
DeterPointNull(plistB);
int len1=GetLength(plistA);
int len2=GetLength(plistB);
pList p=plistA;
pList q=plistB;
//跑完差值
if(len1>len2)
{
for(int i=0;i<len1-len2;i++)
{
p=p->next;
}
}
else
{
for(int i=0;i<len2-len1;i++)
{
q=q->next;
}
}
//查找并返回相交的第一个节点
while (p!=NULL && q!=NULL)
{
if(p==q)
{
return p;
}
p=p->next;
q=q->next;
}
return NULL;
}
5.只给定单链表中某个结点p(并非最后一个结点,即p->next!=NULL)指针,删除该结点 O(1)
思路:如果查找前驱结点,那么时间复杂度必然为O(n),所以此处采取将p->next的结点赋值给p,然后删除p->next结点,从而实现对p结点的删除
bool DeleteNode(pList plist,Node *p)
{
DeterPointNull(plist);
if(p==plist || p==NULL && p->next==NULL)
{
return false;
}
Node *q=p->next;
p->data=q->data;
p->next=q->next;
free(q);
return true;
}
6.只给定单链表中某个节点p(非空节点),在p前面插入一个节点,时间复杂度为O(1)
bool InsertNode(pList plist,Node *p,int val)
{
if(plist==NULL || p==NULL || p==plist)
{
return false;
}
Node *q=(Node *)malloc(sizeof(Node));
q->data=p->data;
q->next=p->next;
p->data=val;
p->next=q;
return true;
}
7.给定单链表头结点,删除链表中倒数第k个结点
bool DeleteBottomK(pList plist,int k)
{
DeterPointNull(plist);
Node *p=plist;
if(plist->next==NULL || k>GetLength(plist) || k<=0)
{
return false;
}
int len =GetLength(plist)-k;//删除节点的位置
for(int i=0;i<k-1;i++)
{
p=p->next;
}
Node *q=p->next;
p->next=p->next->next;
free(q);
return true;
}