补充了每个算法的基本思想,并且画了思路图,源代码都经过调试成功
1.SlistNode.c文件
(1) (不带头结点的)单链表增删查改
#include "SlistNode.h"
SlistNode* slistBuyNode(int x) //申请新的值为x的节点
{
SlistNode *t = (SlistNode*)malloc(sizeof(SlistNode));
t->data = x;
t->next = NULL;
return t;
}
void slistInit(SlistNode **p) //初始化
{
(*p)= NULL;
}
void slistPrint(SlistNode*p) //打印
{
SlistNode* t = p;
for (t = p; t; t = t->next)
{
printf("%d->", t->data);
}
printf("NULL\n");
}
SlistNode* slistFind(SlistNode*p, int x) //查找x
{
SlistNode* t = p;
for (t = p; t; t = t->next)
{
if (t->data == x)
return t;
}
return NULL;
}
void slistInsert(SlistNode**pos, int x) //在pos后插入
{
SlistNode*t = slistBuyNode(x);
t->next = (*pos)->next;
(*pos)->next = t;
}
void slistEraseAfter(SlistNode**p,int x) //删除x
{
SlistNode*t = *p,*t1;
if ((*p)->data == x) //要删除的值x是第一个结点时
{
t1 = *p; //临时备份
*p = t1->next;
free(t1);
t1 = NULL;
}
for (t = *p; t&&t->next; t = t->next) //要删除的值x不是第一个结点时
{
if (t->next->data == x) //t->next即从第二个结点开始扫描
{
t1 = t->next;
t->next = t1->next;
free(t1);
t1 = NULL;
}
}
return 1;
}
void slistPushFront(SlistNode**p, int x) //头插
{
SlistNode*t = slistBuyNode(x);
t->next = (*p);
(*p) = t;
}
void slistPopFront(SlistNode**p) //头删
{
SlistNode *t;
if ((*p) == NULL)
return;
t = (*p)->next;
free((*p));
*p = t;
return;
}
void slistDestory(SlistNode **p) //销毁
{
SlistNode *t = *p;
if ((*p) == NULL)
return ;
while ((*p)->next != NULL)
{
(*p)->next = (*p)->next->next;//不停地后删,直到删光所有结点
free(*p);
*p = NULL; //防止野指针
}
}
void removeall(SlistNode**p, int x) //删除所有值为X的结点
{
SlistNode *t, *t1;
if ((*p) == NULL)
return NULL;
if (((*p)->data == x)) //要删除的x是第一个结点时
{
t = (*p);t1 = t;
*p =t1->next;
free(t1);
t1 = NULL;
}
t = *p; //执行完上述操作之后t指向的原来的*p被释放了,所以要让t指向新的头
while (t->next&&t) //这里用一个while和if-else循环将从第二个结点开始的所有与
{ //x相同的结点删除。
if (t->next->data == x) //t->next即从第二个结点开始扫描
{
t1 = t->next;
t->next = t1->next;
free(t1);
t1 = NULL;
}
else
t = t->next;
}
}
(2)逆置单链表(两种方法)
方法一:先后删,别释放,再头插。具体可以如下图所示。
void reverse1(SlistNode**p) //逆置单链表
{
SlistNode*t; //当前操作的结点
SlistNode*h; //指向新的头结点
SlistNode*oldh; //一直指向旧的头结点
oldh = *p;
h = oldh;
t = oldh->next;
while(t)
{
oldh->next = t->next; //后删
t->next = h; //头插
h = t;
t = oldh->next;
}
*p = h; // 最后的新头是h
}
方法二:断结点,向后转,具体如图:
void reverse2(SlistNode**p) //逆置单链表2
{
SlistNode*h, *c, *t;
h = *p;
c = h->next;
t = c;
h->next = NULL;
while (t)
{
t = t->next;
c->next = h;
h = c;
c = t;
}
*p = h;
}
(3)求两个单链表的第一个公共结点
int comnode(SlistNode**LA, SlistNode**LB) //两个链表公共结点
{
SlistNode*A = *LA, *B = *LB;
int lenA = 0, lenB = 0,gap=0;
for (A = *LA; A; A = A->next)
lenA++;
for (B = *LB; B; B = B->next)
lenB++;
A = *LA; B = *LB; //上述操作之后A与B的指向均已发生变化。
gap = abs(lenA - lenB);
if (lenB > lenA)
{
A = *LB;
B = *LA;
}
for (int i = 0; i < gap; i++)
A = A->next;
for (; A&&B; A = A->next, B = B->next)
if (A->data == B->data) //这里不能是两个指针变量比较
return A->data;
return NULL;
}
(4)合并两个单链表
SlistNode* merge(SlistNode**LA, SlistNode**LB) //合并两个单链表
{
SlistNode*preA = *LA, *L = preA,*A = preA->next, *B = *LB, *nextB = B->next;
while( preA&&A&&nextB&&B)
{
if (preA->data > B->data)
{
B->next = preA; //插入
B = nextB;
nextB = B->next;
}
if (A->data > B->data)
{
B->next = A;
preA->next = B; //插入B
preA = B; //插入的B在preA和A之间
B = nextB;
nextB = nextB->next;
}
else if (A->data <= B->data)
{
preA = A;
A=preA->next;
}
}
while (nextB)//A为空且B不为空时
{
A->next = B;
B = nextB;
}
free(B);
B = NULL;
return L;
}
(5)单循环链表中判断第一个入环点
SlistNode* cycle(SlistNode**h) //单循环链表中判断第一个入环点
{
SlistNode*fast=*h, *slow=fast;
while (fast&&slow) //找相遇点
{
fast = fast->next->next;
slow = slow->next;
if (fast == slow)
break;
}
for (; fast->next && (*h)->next; fast = fast->next, (*h) = (*h)->next)
if (fast == *h)
return fast;
return NULL;
}
(6)约瑟夫环
SlistNode* Josephus(SlistNode**l,int n,int m) //约瑟夫环
{
SlistNode *p, *prep;
p = *l; prep = p;
while (p->next!= *l)
{
p = p->next; //p指向尾结点
}
prep = p; //prep指向尾结点
p = p->next; //p指向第一个结点
while (p&&prep&&n>1)
{
for (int i = 0; i < m-1; i++) //从第一个结点开始报数,则报到第m个结点时,走了m-1步
{
prep = p;
p = p->next;
}
prep->next = p->next;
free(p);
p=prep;
p = p->next;
n--;
}
return p;
}
**
2.SlistNode.h文件
**
#ifndef _SLISTNODE_H_
#define _SLISTNODE_H_
#include <stdio.h>
#include<windows.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <math.h>
typedef struct SlistNode
{
int data;
struct SlistNode* next;
}SlistNode;
void slistPrint(SlistNode *p);
void slistInit(SlistNode **p);
void slistDestory(SlistNode **p);
SlistNode* slistBuyNode(int x);
void slistPopFront(SlistNode**p);
void slistPushFront(SlistNode**p, int x);
SlistNode* slistFind(SlistNode*p, int x);
void slistInsert(SlistNode**pos,int x);
void slistEraseAfter(SlistNode**p,int x);
void removeall(SlistNode**p, int x);
void reverse1(SlistNode**p);
void reverse2(SlistNode**p);
int comnode(SlistNode**LA, SlistNode**LB);
SlistNode* cycle(SlistNode**h);
SlistNode* merge(SlistNode**LA, SlistNode**LB);
SlistNode* Josephus(SlistNode**l, int n, int m);
#endif
3.main.c文件
#include "SlistNode.h"
int main()
{
SlistNode *p;
slistInit(&p);
slistPushFront(&p, 10);
slistPushFront(&p, 9);
slistPushFront(&p, 6);
slistPushFront(&p, 5);
slistPushFront(&p, 4);
slistPushFront(&p, 1);
//slistPopFront(&p);
//slistInsert(&(p->next->next), 9);
slistPrint(p);
//slistEraseAfter(&p,3);
//SlistNode*t = slistFind(p, 3); printf("%d", t->data);
//removeall(&p, 3);
//reverse1(&p);
//reverse2(&p);
/* SlistNode *q;
slistInit(&q);
slistPushFront(&q, 10);
slistPushFront(&q, 9);
slistPushFront(&q, 8);
slistPushFront(&q, 7);
slistPrint(q);*/
/*int r=comnode(&p, &q);
printf("%d\n", r);*/
SlistNode*r=p, *h;
while (r->next)
r = r->next;
r->next = p; //围成一个循环圈:1-2-3-4-5-1-2-3-4-5-1-2-3-4-5......
//r->next = p->next; 第一个结点在外边,其他结点围成循环:1-2-3-4-5-2-3-4-5-2-3-4-5....
//slistPrint(p);
/*h=cycle(&p);
printf("%d\n", h->data); */
//SlistNode*t=Josephus(&p, 6, 3);
//slistPrint(t);
//SlistNode*t=merge(&p, &q);
//slistPrint(t);
system("pause");
return 0;
}