(一)单链表
单链表结构:数据域_data和指针域_pnext,其基本操作如下列代码所示,附有注释说明:
//单链表结构
typedef int ElemType;
typedef struct Node
{
ElemType _data;
struct Node* _pnext;
}Node,*PClist;
//购买节点
Node* BuyNode()
{
Node* pnode = (Node*)malloc(sizeof(Node));
assert(pnode != NULL);
return pnode;
}
//释放节点
void FreeNode(Node* pnode)
{
free(pnode);
}
//初始化链表 购买头结点
void Init_List(PClist plist)
{
if(plist == NULL )
return ;
plist->_pnext = NULL;
}
//单链表头插
bool Insert_Head(PClist plist,ElemType key)
{
if( plist == NULL )
return false;
Node* pnewNode = BuyNode();
if(pnewNode == NULL)
return false;
//给新节点的数据域赋值
pnewNode ->_data = key;
//新节点的_pnext域指向头结点的_pnext
pnewNode ->_pnext = plist->_pnext;
//头结点的_pnext域指向新节点
plist->_pnext = pnewNode;
return true;
}
//单链表尾插
bool Insert_Tail(PClist plist,ElemType key)
{
if( plist == NULL )
return false;
Node* p = plist;
//先走到链表尾部
for(p;p->_pnext != NULL;p= p->_pnext);
//购买新节点
Node* pnewNode = BuyNode();
pnewNode->_data = key;
//新节点的_pnext域指向p的_pnext域
//p的_pnext域指向新节点
pnewNode->_pnext = p->_pnext;
p->_pnext = pnewNode;
return true;
}
//查找某个值是否在链表中 并返回其节点
Node* Search(PClist plist,ElemType key)
{
if(plist == NULL)
return NULL;
Node* p = plist->_pnext;
for(;p != NULL ; p = p->_pnext)
{
if( p->_data == key)
{
return p;
}
}
return NULL;
}
//查找某个值在单链表中的前驱
Node* Search_Prev(PClist plist,ElemType key)
{
if(plist == NULL)
return NULL;
Node* p = plist;
for(;p->_pnext != NULL ; p = p->_pnext)
{
if( p->_pnext->_data == key)
{
return p;
}
}
return NULL;
}
//删除某个节点
//首先查找要删的节点是否在链表中
//如果存在则需要找到被删节点的前驱
//被删节点的前驱的_pnext域指向被删节点的后继
//最后free调要删的节点
bool Delete_Node(PClist plist,ElemType key)
{
if(plist == NULL)
return false;
Node* p = Search(plist,key);
if(p == NULL)
return NULL;
Node* q = Search_Prev(plist,key);
if(q == NULL)
return false;
q->_pnext = p->_pnext;
FreeNode(p);
return true;
}
//统计链表长度
int GetLength(PClist plist)
{
int len = 0;
if(plist == NULL)
return len;
for(Node* p = plist->_pnext;p != NULL;p=p->_pnext)
{
len++;
}
return len ;
}
//判断链表是否为空
bool IsEmpty(PClist plist)
{
return plist->_pnext == NULL;
}
//销毁链表
void Destroy(PClist plist)
{
if(plist == NULL)
return ;
Node* p ;
while(plist ->_pnext != NULL)
{
p = plist->_pnext;
plist->_pnext = p->_pnext;
free(p);
}
}
//打印单链表
void Show(PClist plist)
{
for(Node* p = plist->_pnext; p != NULL; p=p->_pnext)
{
printf("%d ",p->_data);
}
printf("\n");
}
//链表逆置
void Reserve(PClist plist)
{
if(plist == NULL)
return ;
Node *p=plist->_pnext;//plist的下一个节点
plist->_pnext=NULL;//将Plist指向的节点置为空
Node *q=p;//plist的下一个节点
while(p!=NULL)
{
q=p->_pnext;//保存P的所指向的下一节点
p->_pnext=plist->_pnext;//p->next保存plist所指的节点;
plist->_pnext=p;//plist保存p的地址
p=q;//指针p往后跳;
}
}
(二)常见链表面试题(部分,后面继续更新)
(1)判断链表是否有环
//判断链表是否有环
bool IsCircle(PClist plist)
{
if(plist == NULL)
return false;
Node* low = plist;
Node* fast = plist;
while( low && fast -> _pnext)
{
low = low->_pnext;
fast = fast->_pnext;
if(fast ->_pnext != NULL)
{
fast = fast->_pnext;
}
if(fast == low)
{
return true;
}
}
return false;
}
//测试用例
/*Node* p = Search(&head1,3);
Node* q= Search(&head1,10);
q->_pnext = p ;
if(IsCircle(&head2))
{
cout<<"head2 list has circle"<<endl;
}
else
{
cout<<"head2 list has not circle"<<endl;
}
if(IsCircle(&head1))
{
cout<<"head1 list has circle"<<endl;
}
else
{
cout<<"head1 list has not circle"<<endl;
}
*/
(2)寻找环的入口地址
//找到环的入口地址 解法一
Node* Finde_Circle(PClist plist)
{
if(plist == NULL)
return false;
Node* low = plist;
Node* fast = plist;
while( low && fast -> _pnext)
{
low = low->_pnext;
fast = fast->_pnext;
if(fast ->_pnext != NULL)
{
fast = fast->_pnext;
}
if(fast == low)
{
break;
}
}
fast = plist;
while(fast ->_pnext && low->_pnext )
{
fast = fast->_pnext;
low = low->_pnext;
if(fast == low)
{
return low;
}
}
return NULL;
}
//找到环的入口地址 解法二 不是最优
Node* Finde_Circle1(PClist plist)
{
if(plist == NULL)
return false;
Node* low = plist;
Node* fast = plist;
while( low && fast -> _pnext)
{
low = low->_pnext;
fast = fast->_pnext;
if(fast ->_pnext != NULL)
{
fast = fast->_pnext;
}
if(fast == low)
{
break;
}
}
Node *meetnode = low;
Node* p = meetnode;
int count = 1;
while( p->_pnext != meetnode)
{
p = p->_pnext;
count++;
}
Node *pNode1 = plist;
for(int i = 0 ; i < count;i++)
{
pNode1 = pNode1 -> _pnext;
}
Node *pNode2 = plist;
while(pNode1 != pNode2)
{
pNode1 = pNode1 -> _pnext;
pNode2 = pNode2 -> _pnext;
}
return pNode1;
}
//测试用例
/*
Node* pq = Finde_Circle(&head1);
if(pq)
{
cout<<"head1 list circle addr ::"<<pq<<endl;
}
else
{
cout<<"head1 not list circle addr ::"<<pq<<endl;
}
Node* pq1 = Finde_Circle1(&head1);
if(pq1)
{
cout<<"head1 list circle addr ::"<<pq<<endl;
}
else
{
cout<<"head1 not list circle addr ::"<<pq<<endl;
}*/
(3)找出单链表倒数第K个节点
//找单链表倒数第k个节点 定义两个指针 一个先走k-1步,在两个指针同时走,
//当快指针到达尾部时,慢指针刚好指向倒数第K的节点
Node* Find_K_List(PClist plist,int k)
{
if(plist == NULL || k == 0)
return NULL;
Node* pk = plist;
Node* p0 = plist;
for(int i = 0 ; i < k-1 ;++i)
{
if(pk ->_pnext != NULL)
{
pk = pk->_pnext;
}
else
{
cout<<"list xiaoyu k"<<endl;
return NULL;
}
}
while(pk ->_pnext != NULL)
{
pk = pk->_pnext;
p0 = p0->_pnext;
}
return p0;
}
//测试用例
/*
int k ;
cin>>k;
Node* pk = Find_K_List(&head1,k);
Show(&head1);
if(pk)
{
cout<<"倒数第k个节点"<<pk<<endl;
cout<<"倒数第k个节点"<<pk->_data<<endl;
}
else
{
cout<<"未找到倒数第k个节点"<<endl;
}
*/
(4)找出单链表的中间节点
/*找单链表的中间节点 快指针一次走两步 慢指针一次走一步
当快指针到达尾部时,如果链表长度为奇数,那么慢指针所指的就是中间节点
如果链表长度为偶数,那么慢指针和它的下一个都是中间节点
*/
Node* Find_Middle_List(PClist plist)
{
if(plist == NULL)
return NULL;
Node* fast = plist;
Node* low = plist;
while(low && fast->_pnext)
{
low = low->_pnext;
fast = fast->_pnext;
if(fast->_pnext != NULL)
{
fast = fast->_pnext;
}
}
return low;
}
//测试用例
/*
Node *mid = Find_Middle_List(&head2);
if(mid)
{
cout<<"this list mid data is "<<mid->_data<<endl;
}else
{
cout<<"this list mid data is "<<mid->_data<<endl;
}
*/
(5)将链表的元素从尾到头打印
//如何从尾到头输出链表
void Print_Reserve(PClist plist)
{
if(plist == NULL)
return ;
stack<Node*> st;
for(Node* p = plist->_pnext;p != NULL ;p = p->_pnext)
{
st.push(p);
}
while(!st.empty())
{
cout<<(st.top())->_data<<" ";
st.pop();
}
cout<<endl;
}
等待更新。。。。。