前面介绍过,线性表分为两种(顺序表和链表),它们各有优缺。对于顺序表而言,对元素遍历以及寻找是相当便利的,但是它最大的缺点就是在插入和删除某个元素时需要移动大量数据,这显然要耗费时间,后来发现链式存储结构恰好能解决这个问题。
在顺序结构中,只需要将数据元素信息存储就好了,但是在链式结构中除了要存数据元素信息外,还要存储它的后继元素的存储地址。下来总结一些有关链式存储结构的小知识:
(1)数据域:把存储数据元素信息的域称为数据域;
(2)指针域:把存储直接后继位置的域称为指针域,指针域中存储的信息称为指针或链;
(3)结 点:数据域和指针域这两部分信息组成某个数据元素的存储映像,称为结点;
(4)头结点:在单链表的第一个结点前附设的一个结点(只是为了方便对链表进行操作);
(5)头结点的特点:其数据域可以不存储任何信息,头结点的指针域存储指向第一个结点的指针,如下图。
下面介绍一些单链表的基本操作:
void PushBack(pLinkList pList,DataType x); //在链表尾插
void PopBack(pLinkList pList); //尾删
void PushFront(pLinkList pList,DataType x);//头插
void PopFront(pLinkList pList); //头删
void PrintList(pLinkList pList); //打印链表
void Insert(pLinkList pList,pLinkNode pos,DataType x); //在指定位置插入元素x
void Erase(pLinkList pList,pLinkNode pos); //删除指定位置的元素
void Remove(pLinkList pList,DataType x); //删除一个元素X
void RemoveAll(pLinkList pList,DataType x);//删除所有元素x
void Bubble(pLinkList pList); //对链表进行排序
(1)尾插:进行尾插时我们需要考虑以下几点
@空链表时,将新开辟的节点赋值给头指针所指向的下一结点,并将尾插结点的指针域置为空即可;
@有节点的情况下,先找到链表的尾部然后进行插入。如下图所示:
代码实现:
void PushBack(pLinkList pList,DataType x)
{
pLinkNode cur = NULL;
pLinkNode NewNode=NULL;
assert(pList);
NewNode=CreateNode(x);
cur = pList->pHead;
if(NULL==pList->pHead) //空链表情况
{
pList->pHead=NewNode;
NewNode->next=NULL;
return;
}
while(cur->next!=NULL) //找到最后一个节点
{
cur=cur->next;
}
cur->next=NewNode;
}
2.尾删
@空链表情况直接返回;
@只有一个节点的情况;
@大于1个节点,一种方法是在找最后一个结点的时候将它的前一个结点保存下来,因为在删除后我们需要将目前倒数第二个结点的指针域置为空;另一种方法就是不需要记录它的前一个结点,我们只需要通过cur指针找到链表的倒数第二个结点就可以了,再通过倒数第二个结点的指针域找到最后一个结点;
void PopBack(pLinkList pList)
{
pLinkNode cur = NULL;
assert(pList);
cur=pList->pHead;
if(NULL==pList->pHead)
{
return ;
}
else
{
if(NULL==cur->next)
{
free(cur);
pList->pHead=NULL;
}
else
{
//大于1个节点,先找到倒数第二个节点
while(cur->next->next!=NULL)
{
cur=cur->next;
}
free(cur->next);
cur->next=NULL;
}
}
}
3.头插
@链表为空;
@有节点的情况,改变指针域的指向。
void PushFront(pLinkList pList,DataType x)
{
//1.空链表情况
//2.有节点的情况
pLinkNode cur = NULL;
pLinkNode NewNode=NULL:
NewNode=CreateNode(x);
assert(pList);
cur = pList->pHead;
if(NULL==pList->pHead)
{
pList->pHead=NewNode;
NewNode->next=NULL;
return;
}
NewNode->next=cur; //有节点的情况
pList->pHead=NewNode;
printf("PushFront successfully!\n");
}
4.头删
@空链表直接返回;
@有节点情况改变指针指向。
void PopFront(pLinkList pList)
{
//1.空链表情况
//2.有节点的情况
pLinkNode cur = NULL;
pLinkNode del = NULL;
assert(pList);
if(NULL==pList->pHead)
{
return ;
}
else
{
cur=pList->pHead->next;
del=pList->pHead;
free(del);
pList->pHead=cur;
}
printf("PopFront successfully!\n");
}
5.在指定位置插入某个元素
@插入时先创建新节点,然后就是改变指针指向问题;
@在指定位置插入时又分为两种情况,在指定位置前插入和指定位置后插入。
void InsertFront(pLinkList pList,pLinkNode pos,DataType x)
{
pLinkNode cur = NULL;
pLinkNode NewNode=NULL;
assert(pList);
NewNode=CreateNode(x);
cur=pList->pHead;
if(NULL==cur)
{
PushFront(pList,x);
}
else
{
while(cur!=pos)
{
cur=cur->next;
}
NewNode->next=cur->next;
cur->next=NewNode;
}
}
void InsertBack(pLinkList pList,pLinkNode pos,DataType x)
{
pLinkNode cur = NULL;
pLinkNode NewNode=NULL;
assert(pList);
NewNode=CreateNode(x);
cur=pList->pHead;
if(NULL==cur)
{
PushFront(pList,x);
}
else
{
while(cur->next!=pos)
{
cur=cur->next;
}
NewNode->next=cur->next;
cur->next=NewNode;
}
}
6.删除
@删除函数又分为删除第一次查找到的指定元素和删除所有指定元素;
@删除时需要考虑空链表,有一个节点和多个节点的情况;有一个节点时先进行判断是否是指定要删除的对象,对于多个节点问题先要看一个特殊情况,如果要删除的对象就是首节点只需要将头指针指向原来第二个节点的位置,否则要进行遍历查找到要删除的对象,删除所有指定元素也是类似的。
void Remove(pLinkList pList,DataType x)
{
pLinkNode cur=NULL;
pLinkNode prev=NULL;
pLinkNode del=NULL;
assert(pList);
cur=pList->pHead;
prev=pList->pHead;
if(NULL==pList->pHead) //空链表
{
return;
}
if(NULL==cur->next) //只有一个节点
{
if(cur->data==x)
{
free(cur->next);
pList->pHead=NULL;
return;
}
}
else
{
while(cur!=NULL)
{
if(cur->data==x)
{
del=cur;
pList->pHead=cur->next;
free(del);
return;
}
cur=cur->next;
while(cur!=NULL)
{
if(cur->data==x)
{
prev->next=cur->next;
free(cur);
return;
}
prev=cur;
cur=cur->next;
}
}
void RemoveAll(pLinkList pList,DataType x)
{
pLinkNode cur=NULL;
pLinkNode prev=NULL;
assert(pList);
cur=pList->pHead;
prev=pList->pHead;
if(NULL==pList->pHead)
{
return;
}
while(cur!=NULL)
{
while(NULL==cur->next)
{
if(cur->data==x)
{
free(cur->next);
pList->pHead=NULL;
return;
}
if(pList->pHead->data==x)
{
pList->pHead=cur->next;
free(cur);
cur=pList->pHead;
}
}
}
cur=cur->next;
prev=pList->pHead;
while(cur)
{
if(cur->data==x)
{
prev->next=cur->next;
free(cur);
cur=prev;
}
prev=cur;
cur->next;
}
}
7.删除指定位置的元素
void Erase(pLinkList pList,pLinkNode pos)
{
pLinkNode cur=NULL;
pLinkNode prev=NULL;
pLinkNode del=NULL;
assert(pList);
cur=pList->pHead;
prev=pList->pHead;
if(NULL==pList->pHead) //空链表
{
return;
}
if(NULL==cur->next)
{
if(cur==pos) //只有一个节点且这个节点就是pos位置
{
free(pList->pHead);
pList->pHead=NULL;
}
return;
}
if(cur==pos) //多个节点时首节点就是pos位置
{
del=cur;
pList->pHead=cur->next;
free(del);
return;
}
cur=cur->next;
while(cur)
{
if(cur==pos)
{
prev->next=cur->next;
free(cur);
return;
}
prev=cur;
cur=cur->next;
}
}
8.对链表进行排序
void BubbleSort(pLinkList pList)
{
pLinkNode cur=NULL;
pLinkNode tail=NULL;
DataType tmp=0;
assert(pList);
cur=pList->pHead;
if(NULL==pLinkList->pHead||NULL==pLinkList->pHead->next)
{
return;
}
while(cur!=tail)
{
while(cur->next!=tail)
{
if((cur->data )> (cur->next->data))
{
tmp=cur->data;
cur->data=cur->next->data;
cur->next->data=tmp;
}
cur=cur->next; //cur向后移动进行下一次冒泡
}
tail=cur; // 排序一趟tail指针向前走一个直至cur=tail排序完成
cur=pList->pHead; //保证每次的外层循环从首节点开始
}
}
LinkList.h
#ifdef _LINKLIST__H_
#define _LINKLIST__H_
#include<stdio.h>
#include<stdlib.h>
#include<assert.h>
enum OP
{
EXIT,
PUSHBACK,
POPBACK,
PUSHFRONT,
POPFRONT,
INSERT,
REMOVE,
REMOVEALL,
ERASE,
SORT,
PRINT
};
typedef int DataType;
typedef struct LinkNode
{
DataType data;
struct LinkNode *next;
}LinkNode,*pLinkNode;
typedef struct LinkList
{
pLinkNode pHead;
}LinkList,*pLinkList;
void InitLinkList(pLinkList pList); //初始化链表
void PrintLinkList(pLinkList pList); //打印链表
void DestroyLinkList(pLinkList pList); //销毁链表
void PushBack(pLinkList pList,DataType x); //尾插
void PopBack(pLinkList pList); //尾删
void PushFront(pLinkList pList,DataType x); //前插
void PopFront(pLinkList pList); //前删
pLinkNode FindNode(pLinkList pList,DataType x); //找节点
void Insert(PlinkList pList,pLinkNode pos,DataType x); //在特定位置插入x元素
void Erase(PlinkList pList,pLinkNode pos); //在特定位置删除x元素
void Remove(pLinkList pList,DataType x); //删除链表中第一次出现的x元素
void RemoveAll(pLinkList pList,DataType x); //删除链表中所有x元素
void BubbleSort(pLinkList pList); //对链表进行冒泡排序
void menu();
#endif
LinkList.c
#include"LinkList.h"
void InitLinkList(pLinkList pList)
{
assert(pList);
pList->pHead=NULL;
}
void PrintLinkList(pLinkList pList)
{
pLinkNode cur=NULL;
assert(pList);
cur=pList->pHead;
while(NULL!=cur)
{
printf("%d->",cur->data);
cur=cur->next;
}
printf("over\n");
}
void DestroyLinkList(pLinkList pList)
{
pLinkNode prev = NULL;
pLinkNode cur =NULL;
assert(pList);
cur = pList->pHead;
if (NULL == pList->pHead) //空链表的情况
{
return;
}
while (cur != NULL)
{
prev = cur;
cur = cur->next;
free(prev);
}
pList->pHead = NULL;
}
pLinkNode CreateNode(DataType x)
{
pLinkNode NewNode=NULL;
NewNode=(pLinkNode)malloc(sizeof(LinkNode));
if(NULL==NewNode)
{
printf("out of memory\n");
exit(1);
}
NewNode->data=x;
NewNode->next=NULL;
return NewNode;
}
void PushBack(pLinkList pList,DataType x)
{
pLinkNode cur = NULL;
pLinkNode NewNode=NULL;
assert(pList);
NewNode=CreateNode(x);
cur = pList->pHead;
if(NULL==pList->pHead) //空链表情况
{
pList->pHead=NewNode;
NewNode->next=NULL;
return;
}
while(cur->next!=NULL) //找到最后一个节点
{
cur=cur->next;
}
cur->next=NewNode;
}
void PopBack(pLinkList pList)
{
pLinkNode cur = NULL;
assert(pList);
cur=pList->pHead;
if(NULL==pList->pHead)
{
return ;
}
else
{
if(NULL==cur->next)
{
free(cur);
pList->pHead=NULL;
}
else
{
//大于1个节点,先找到倒数第二个节点
while(cur->next->next!=NULL)
{
cur=cur->next;
}
free(cur->next);
cur->next=NULL;
}
}
}
void PushFront(pLinkList pList,DataType x)
{
//1.空链表情况
//2.有节点的情况
pLinkNode cur = NULL;
pLinkNode NewNode=NULL:
NewNode=CreateNode(x);
assert(pList);
cur = pList->pHead;
if(NULL==pList->pHead)
{
pList->pHead=NewNode;
NewNode->next=NULL;
return;
}
NewNode->next=cur; //有节点的情况
pList->pHead=NewNode;
printf("PushFront successfully!\n");
}
void PopFront(pLinkList pList)
{
//1.空链表情况
//2.有节点的情况
pLinkNode cur = NULL;
pLinkNode del = NULL;
assert(pList);
if(NULL==pList->pHead)
{
return ;
}
else
{
cur=pList->pHead->next;
del=pList->pHead;
free(del);
pList->pHead=cur;
}
printf("PopFront successfully!\n");
}
pLinkNode FindNode(pLinkList pList,DataType x)
{
pLinkNode cur = NULL;
pLinkNode find = NULL;
assert(pList);
cur =pList->pHead;
while(cur!=NULL)
{
if(cur->data==x)
{
return cur;
}
cur=cur->next;
}
return NULL;
}
void InsertFront(pLinkList pList,pLinkNode pos,DataType x)
{
pLinkNode cur = NULL;
pLinkNode NewNode=NULL;
assert(pList);
NewNode=CreateNode(x);
cur=pList->pHead;
if(NULL==cur)
{
PushFront(pList,x);
}
else
{
while(cur!=pos)
{
cur=cur->next;
}
NewNode->next=cur->next;
cur->next=NewNode;
}
}
void InsertBack(pLinkList pList,pLinkNode pos,DataType x)
{
pLinkNode cur = NULL;
pLinkNode NewNode=NULL;
assert(pList);
NewNode=CreateNode(x);
cur=pList->pHead;
if(NULL==cur)
{
PushFront(pList,x);
}
else
{
while(cur->next!=pos)
{
cur=cur->next;
}
NewNode->next=cur->next;
cur->next=NewNode;
}
}
void Erase(pLinkList pList,pLinkNode pos)
{
pLinkNode cur=NULL;
pLinkNode prev=NULL;
pLinkNode del=NULL;
assert(pList);
cur=pList->pHead;
prev=pList->pHead;
if(NULL==pList->pHead) //空链表
{
return;
}
if(NULL==cur->next)
{
if(cur==pos) //只有一个节点且这个节点就是pos位置
{
free(pList->pHead);
pList->pHead=NULL;
}
return;
}
if(cur==pos) //多个节点时首节点就是pos位置
{
del=cur;
pList->pHead=cur->next;
free(del);
return;
}
cur=cur->next;
while(cur)
{
if(cur==pos)
{
prev->next=cur->next;
free(cur);
return;
}
prev=cur;
cur=cur->next;
}
}
void Remove(pLinkList pList,DataType x)
{
pLinkNode cur=NULL;
pLinkNode prev=NULL;
pLinkNode del=NULL;
assert(pList);
cur=pList->pHead;
prev=pList->pHead;
if(NULL==pList->pHead) //空链表
{
return;
}
if(NULL==cur->next) //只有一个节点
{
if(cur->data==x)
{
free(cur->next);
pList->pHead=NULL;
return;
}
}
else
{
while(cur!=NULL)
{
if(cur->data==x)
{
del=cur;
pList->pHead=cur->next;
free(del);
return;
}
cur=cur->next;
while(cur!=NULL)
{
if(cur->data==x)
{
prev->next=cur->next;
free(cur);
return;
}
prev=cur;
cur=cur->next;
}
}
void RemoveAll(pLinkList pList,DataType x)
{
pLinkNode cur=NULL;
pLinkNode prev=NULL;
assert(pList);
cur=pList->pHead;
prev=pList->pHead;
if(NULL==pList->pHead)
{
return;
}
while(cur!=NULL)
{
while(NULL==cur->next)
{
if(cur->data==x)
{
free(cur->next);
pList->pHead=NULL;
return;
}
if(pList->pHead->data==x)
{
pList->pHead=cur->next;
free(cur);
cur=pList->pHead;
}
}
}
cur=cur->next;
prev=pList->pHead;
while(cur)
{
if(cur->data==x)
{
prev->next=cur->next;
free(cur);
cur=prev;
}
prev=cur;
cur->next;
}
}
void BubbleSort(pLinkList pList)
{
pLinkNode cur=NULL;
pLinkNode tail=NULL;
DataType tmp=0;
assert(pList);
cur=pList->pHead;
if(NULL==pLinkList->pHead||NULL==pLinkList->pHead->next)
{
return;
}
while(cur!=tail)
{
while(cur->next!=tail)
{
if((cur->data )> (cur->next->data))
{
tmp=cur->data;
cur->data=cur->next->data;
cur->next->data=tmp;
}
cur=cur->next; //cur向后移动进行下一次冒泡
}
tail=cur; // 排序一趟tail指针向前走一个直至cur=tail排序完成
cur=pList->pHead; //保证每次的外层循环从首节点开始
}
}
void menu()
{
printf("***********LinkList***************\n");
printf("*****0.Exit********1.Init*********\n");
printf("*****2.PushBack*****3.PopBack*****\n");
printf("*****4.PushFront*****5.PopFront***\n");
printf("*****6.Insert****7.Erase**********\n");
printf("*****8.Remove*******9.RemoveAll***\n");
printf("*****10.BubbleSort*****11.Print***\n");
}
test.c
#include"LinkList.h"
void test()
{
LinkList list;
pLinkNode pos = NULL;
InitLinkList(&list);
int input = 1;
DataType x = 0;
DataType y = 0;
while (input)
{
menu();
printf("please your choice:");
scanf("%d",&input);
switch (input)
{
case EXIT:
DestroyLinkList(&list);
break;
case PUSHBACK:
printf("please input a number of insertion:");
scanf("%d",&x);
PushBack(&list, x);
break;
case POPBACK:
PopBack(&list);
break;
case PUSHFRONT:
printf("please input a number of insertion:");
scanf("%d", &x);
PushFront(&list, x);
break;
case POPFRONT:
PopFront(&list);
break;
case INSERT:
printf("please input a number of insertion:");
scanf("%d", &x);
printf("please input a number of the data of pos:");
scanf("%d", &y);
pos = Find(&list, x);
InsertFront(&list,pos,x);
InsertBack(&list,pos,x);
break;
case REMOVE:
printf("please input a number of delete:");
scanf("%d", &x);
Remove(&list, x);
break;
case REMOVEALL:
printf("please input a number of delete:");
scanf("%d", &x);
RemoveAll(&list, x);
break;
case ERASE:
printf("please input a number of delete:");
scanf("%d", &x);
pos = find(&list,x);
Erase(&list, pos);
break;
case SORT:
BubbleSort(&list);
break;
case PRINT:
PrintLinkList(&list);
break;
}
}
}
int main()
{
test();
system("pause");
return 0;
}