链表是线性表的另一种表示方法,其特点是每个元素包含数据域和指针域,指针域的存在使得链表元素之间在空间上不必连续(即地址不连续),并且链表元素节点可以用时分配,比顺序表要灵活,但如果节点数较多,耗费空间资源比顺序表要多
链表有单向链表、双向链表、十字链表、循环链表等,这里仅简单介绍单向链表,其它链表形式大同小异
其基本定义:
typedef struct LIST{
int idata;
struct LIST *ptNext;
}T_List, *PT_List;
idata是节点的数据域,ptNext为指针域,指向下一个节点
为链表提供一个头节点,会给链表(对头部节点的)操作带来极大的便利,下面会给出无头节点和有头节点两个版本的代码
链表主要操作有:
1、创建一个链表:PT_List createList(void)
在无头节点版本中,创建链表要知道第一个数据的值
在有头节点版本中,创建链表只需要创建一个头节点,不需要有实际的元素
2、从链表中查找指定元素节点:PT_List findInList(int iX, PT_List ptHead)
两版本查找元素过程是一致的,只需要判空然后按照节点指针域遍历节点的数据域即可
3、从链表中修改指定节点的数据域:PT_List alterInList(int iNew, int iPre, PT_List ptHead, int iFlag)
两版本的修改节点数据域过程一致,根据数据域找到指定节点进行修改即可
4、向链表插入元素节点:PT_List addToList(int iNew, int iPre, PT_List ptHead, int iFlag)
插入节点可以分为从链表头插入、从链表尾插入、从链表中某个节点后插入
对于无头节点版本,无论哪种插入,都需要判空,如果链表为空,则创建第一个节点,如果不为空,从链表头插入时,可以采用两种方法:①创建新节点,新节点的指针域指向原链表第二个节点,然后原链表第一个节点的指针域指向新节点,这样就把新节点插入到原链表的第一、第二节点之间,然后把新节点数据域与第一个节点数据域交换即可;②创建新节点,指针域指向链表第一个节点,保存新节点数据域后,修改链表头部指针,指向新节点,这要求子函数传入参数为二重指针
对于有头节点版本,从链表头插入时,只需要按照①的方法插入即可,数据域无需交换,因为头节点只起标志性作用,不作为真实数据节点
后面两种插入方法,有无头节点其过程都是一致的(除了无头节点情况需要判空以外)
从链表尾插入时,遍历找到尾节点(单链表查找依据是指针域为NULL),然后让尾节点指向新节点即可从某个节点后插入时,遍历找到特定节点(查找依据是数据域),然后用变量暂存特定节点的下一个节点,插入过程类似从链表头插入
5、从链表中删除指定节点PT_List deleteFromList(int iX, PT_List ptHead, int iFlag)
删除节点也可以分为删除头节点、尾节点、中间节点三种情况,方法类似插入节点
无头节点版本代码:
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#ifdef DEBUG_LIST_VERSION_1
#define MENU_EXIT 0
#define MENU_FIND 1
#define MENU_ADD 2
#define MENU_ALTER 3
#define MENU_DELETE 4
#define MENU_PRINT 5
#define ADD_IN_HEAD 1
#define ADD_IN_TAIL 2
#define ADD_IN_MID 3
#define DELETE_ONE_VALUE 1
#define DELETE_ALL_VALUE 2
#define ALTER_ONE 1
#define ALTER_ALL 2
typedef struct LIST{
int idata;
struct LIST *ptNext;
}T_List, *PT_List;
PT_List createList(void)
{
int i, iNum;
PT_List ptHead, ptPre, ptTmp;
printf("Enter the num of nodes: ");
scanf_s("%d", &iNum);
if (iNum <= 0)
{
printf("Err: num <= 0\r\n");
return NULL;
}
printf("Enter your data: ");
ptHead = (PT_List)malloc(sizeof T_List);
scanf_s("%d", &ptHead->idata);
ptHead->ptNext = NULL;
ptPre = ptHead;
for (i = 1; i < iNum; i++)
{
ptTmp = (PT_List)malloc(sizeof T_List);
scanf_s("%d", &ptTmp->idata);
ptTmp->ptNext = NULL;
ptPre->ptNext = ptTmp;
ptPre = ptTmp;
}
return ptHead;
}
void printList(PT_List ptHead)
{
PT_List ptTmp = ptHead;
printf("\r\n");
if(!ptTmp)
printf("List is empty\r\n");
while (ptTmp)
{
printf("%d ", ptTmp->idata);
ptTmp = ptTmp->ptNext;
}
printf("\r\n\r\n");
}
PT_List findTheListTail(PT_List ptHead)
{
PT_List ptTmp = ptHead;
while (ptTmp->ptNext)
ptTmp = ptTmp->ptNext;
return ptTmp;
}
PT_List findBeforeOne(int iX, PT_List ptHead)
{
PT_List ptTmp = ptHead, ptPre = NULL;
int i = 1;
while (ptTmp->idata != iX && ptTmp->ptNext)
{
ptPre = ptTmp;
ptTmp = ptTmp->ptNext;
i++;
}
if (ptTmp->idata != iX)
{
printf("Can't Find the node %d\r\n", iX);
return NULL;
}
printf("Find the node in %d\r\n", --i);
return ptPre;
}
PT_List findInList(int iX, PT_List ptHead)
{
PT_List ptTmp = ptHead;
int i = 1;
if (!ptHead)
{
printf("List is empty\r\n");
return NULL;
}
while (ptTmp->idata != iX && ptTmp->ptNext)
{
ptTmp = ptTmp->ptNext;
i++;
}
if (ptTmp->idata != iX)
{
printf("Can't Find the node %d\r\n", iX);
return NULL;
}
return ptTmp;
}
PT_List addToList(int iNew, int iPre, PT_List *pptHead, int iFlag)
{
PT_List ptTmp = NULL, ptNew;
int iTmp;
if (iFlag != ADD_IN_HEAD && iFlag != ADD_IN_TAIL && iFlag != ADD_IN_MID)
{
printf("Err in iFlag\r\n");
return NULL;
}
ptNew = (PT_List)malloc(sizeof T_List);
if (!ptNew)
{
printf("Err in memory\r\n");
return NULL;
}
if (!*pptHead)
{
*pptHead = ptNew;
(*pptHead)->idata = iNew;
(*pptHead)->ptNext = NULL;
return *pptHead;
}
if (iFlag == ADD_IN_HEAD)
{
ptNew->ptNext =( *pptHead)->ptNext;
(*pptHead)->ptNext = ptNew;
iTmp = iNew;
ptNew->idata = (*pptHead)->idata;
(*pptHead)->idata = iTmp;
}
else if (iFlag == ADD_IN_TAIL)
{
ptTmp = findTheListTail(*pptHead);
ptTmp->ptNext = ptNew;
ptNew->ptNext = NULL;
ptNew->idata = iNew;
}
else if (iFlag == ADD_IN_MID)
{
ptTmp = findInList(iPre, (*pptHead));
if (!ptTmp)
{
printf("Err in the location\r\n");
free(ptNew);
return NULL;
}
ptNew->ptNext = ptTmp->ptNext;
ptTmp->ptNext = ptNew;
ptNew->idata = iNew;
}
return *pptHead;
}
PT_List alterInList(int iNew, int iPre, PT_List ptHead, int iFlag)
{
PT_List ptTmp;
if (iFlag != ALTER_ONE && iFlag != ALTER_ALL)
{
printf("Err in iFlag\r\n");
return NULL;
}
ptTmp = findInList(iPre, ptHead);
if (!ptTmp)
return NULL;
do
{
ptTmp->idata = iNew;
if (iFlag == ALTER_ONE)
break;
ptTmp = findInList(iPre, ptHead);
} while (ptTmp);
return ptHead;
}
PT_List deleteFromList(int iX, PT_List *pptHead, int iFlag)
{
PT_List ptPre, ptTmp = NULL;
if(iFlag != DELETE_ONE_VALUE && iFlag != DELETE_ALL_VALUE)
{
printf("Err in iFlag\r\n");
return NULL;
}
if (!(*pptHead)->ptNext)
{
ptTmp = *pptHead;
*pptHead = NULL;
free(ptTmp);
return NULL;
}
while ((*pptHead)->idata == iX)
{
ptTmp = (*pptHead)->ptNext;
(*pptHead)->idata = ptTmp->idata;
(*pptHead)->ptNext = ptTmp->ptNext;
free(ptTmp);
if (iFlag == DELETE_ONE_VALUE)
return *pptHead;
}
ptPre = findBeforeOne(iX, *pptHead);
if (!ptPre)
{
printf("Err in the element\r\n");
return NULL;
}
while (ptPre)
{
ptTmp = ptPre->ptNext;
ptPre->ptNext = ptTmp->ptNext;
free(ptTmp);
if (iFlag == DELETE_ONE_VALUE)
break;
ptPre = findBeforeOne(iX, *pptHead);
}
return *pptHead;
}
int menu(PT_List *pptHead)
{
int iNum, iEle, iTmp = 0;
printf( "Enter\r\n"
"0 to exit\r\n"
"1 to find\r\n"
"2 to add\r\n"
"3 to alter\r\n"
"4 to delete\r\n"
"5 to print\r\n");
scanf_s("%d", &iNum);
switch (iNum)
{
case MENU_EXIT:
return -1;
case MENU_FIND:
printf("Enter the element: ");
scanf_s("%d", &iEle);
findInList(iEle, *pptHead);
break;
case MENU_ADD:
printf( "Enter\r\n"
"1 to add in head\r\n"
"2 to add in tail\r\n"
"3 to add in mid\r\n");
scanf_s("%d", &iNum);
if (iNum == ADD_IN_MID)
{
printf("Enter the num before the one to be altered: ");
scanf_s("%d", &iTmp);
}
printf("Enter the element: ");
scanf_s("%d", &iEle);
addToList(iEle, iTmp, pptHead, iNum);
break;
case MENU_ALTER:
printf("Enter\r\n"
"1 to alter one\r\n"
"2 to alter all\r\n");
scanf_s("%d", &iNum);
printf("Enter the Pre element: ");
scanf_s("%d", &iTmp);
printf("Enter the new element: ");
scanf_s("%d", &iEle);
alterInList(iEle, iTmp, *pptHead, iNum);
break;
case MENU_DELETE:
printf("Enter\r\n"
"1 to delete in one\r\n"
"2 to delete in all\r\n");
scanf_s("%d", &iNum);
printf("Enter the element: ");
scanf_s("%d", &iEle);
deleteFromList(iEle, pptHead, iNum);
break;
case MENU_PRINT:
printList(*pptHead);
break;
}
return 0;
}
int main(void)
{
PT_List ptHead;
ptHead = createList();
if (!ptHead)
return -1;
while (menu(&ptHead) >= 0);
return 0;
}
#endif
有头节点版本代码:
#include <stdio.h>
#include <stdlib.h>
#include "config.h"
#ifdef DEBUG_LIST_VERSION_2
#define MENU_EXIT 0
#define MENU_FIND 1
#define MENU_ADD 2
#define MENU_ALTER 3
#define MENU_DELETE 4
#define MENU_PRINT 5
#define ADD_IN_HEAD 1
#define ADD_IN_TAIL 2
#define ADD_IN_MID 3
#define ALTER_ONE 1
#define ALTER_ALL 2
#define DELETE_ONE 1
#define DELETE_ALL 2
typedef struct LIST {
int idata;
struct LIST *ptNext;
}T_List, *PT_List;
PT_List createList(void)
{
PT_List ptPre, ptNew, ptHead;
int iNum;
printf("Enter the num of nodes: ");
scanf_s("%d", &iNum);
if (iNum < 0)
{
printf("Err in the num of nodes\r\n");
return NULL;
}
ptHead = (PT_List)malloc(sizeof T_List);
ptHead->ptNext = NULL;
ptPre = ptHead;
printf("Enter your data: ");
while (iNum-- > 0)
{
ptNew = (PT_List)malloc(sizeof T_List);
scanf_s("%d", &ptNew->idata);
ptNew->ptNext = NULL;
ptPre->ptNext = ptNew;
ptPre = ptNew;
}
return ptHead;
}
void printList(PT_List ptHead)
{
PT_List ptTmp = ptHead->ptNext;
printf("\r\n");
if (!ptTmp)
printf("List is empty\r\n");
while (ptTmp)
{
printf("%d ", ptTmp->idata);
ptTmp = ptTmp->ptNext;
}
printf("\r\n\r\n");
}
int isEmpty(PT_List ptHead)
{
return ptHead->ptNext == NULL ? 1: 0;
}
PT_List findListTail(PT_List ptHead)
{
PT_List ptTmp = ptHead->ptNext;
if (isEmpty(ptHead))
{
printf("List is empty\r\n");
return NULL;
}
while (ptTmp->ptNext)
ptTmp = ptTmp->ptNext;
return ptTmp;
}
PT_List findInList(int iX, PT_List ptHead)
{
PT_List ptTmp = ptHead->ptNext;
int i = 1;
if (isEmpty(ptHead))
{
printf("List is empty\r\n");
return NULL;
}
while (ptTmp->idata != iX && !isEmpty(ptTmp))
{
i++;
ptTmp = ptTmp->ptNext;
}
if (ptTmp->idata != iX)
{
printf("Can't find the %d\r\n", iX);
return NULL;
}
printf("Find the node %d in %d\r\n", iX, i);
return ptTmp;
}
PT_List addToList(int iNew, int iPre, PT_List ptHead, int iFlag)
{
PT_List ptNew, ptTmp, ptPre;
if (iFlag != ADD_IN_HEAD && iFlag != ADD_IN_TAIL && iFlag != ADD_IN_MID)
{
printf("Err in iFlag\r\n");
return NULL;
}
ptNew = (PT_List)malloc(sizeof T_List);
ptNew->idata = iNew;
ptNew->ptNext = NULL;
switch (iFlag)
{
case ADD_IN_HEAD:
ptTmp = ptHead->ptNext;
ptHead->ptNext = ptNew;
ptNew->ptNext = ptTmp;
break;
case ADD_IN_TAIL:
ptPre = findListTail(ptHead);
ptPre->ptNext = ptNew;
break;
case ADD_IN_MID:
ptPre = findInList(iPre, ptHead);
ptTmp = ptPre->ptNext;
ptNew->ptNext = ptTmp;
ptPre->ptNext = ptNew;
break;
}
return ptHead;
}
PT_List alterInList(int iNew, int iOld, PT_List ptHead, int iFlag)
{
PT_List ptTmp;
if (iFlag != ALTER_ONE && iFlag != ALTER_ALL)
{
printf("Err in iFlag\r\n");
return NULL;
}
ptTmp = findInList(iOld, ptHead);
if (!ptTmp)
return NULL;
while (ptTmp)
{
ptTmp->idata = iNew;
if (iFlag == ALTER_ONE)
break;
ptTmp = findInList(iOld, ptHead);
}
return ptHead;
}
PT_List findBeforeOne(int iEle, PT_List ptHead)
{
PT_List ptTmp = ptHead->ptNext, ptPre = ptHead;
if (isEmpty(ptHead))
{
printf("List is empty\r\n");
return NULL;
}
while (ptTmp->idata != iEle && ptTmp->ptNext)
{
ptPre = ptTmp;
ptTmp = ptTmp->ptNext;
}
if (ptTmp->idata != iEle)
{
printf("Can't find the element\r\n");
return NULL;
}
return ptPre;
}
PT_List deleteFromList(int iEle, PT_List ptHead, int iFlag)
{
PT_List ptPre, ptTmp;
if (iFlag != DELETE_ONE && iFlag != DELETE_ALL)
{
printf("Err in iFlag\r\n");
return NULL;
}
ptPre = findBeforeOne(iEle, ptHead);
while (ptPre)
{
ptTmp = ptPre->ptNext;
if (!ptTmp->ptNext)
ptPre->ptNext = NULL;
else
ptPre->ptNext = ptTmp->ptNext;
free(ptTmp);
if (iFlag == DELETE_ONE)
break;
ptPre = findBeforeOne(iEle, ptHead);
}
return ptHead;
}
int menu(PT_List ptHead)
{
int iNum, iEle, iLoc = 0;
printf("Enter\r\n"
"0 to exit\r\n"
"1 to find\r\n"
"2 to add\r\n"
"3 to alter\r\n"
"4 to delete\r\n"
"5 to print\r\n");
scanf_s("%d", &iNum);
switch (iNum)
{
case MENU_EXIT:
return -1;
case MENU_FIND:
printf("Enter the element to be found: ");
scanf_s("%d", &iEle);
findInList(iEle, ptHead);
break;
case MENU_ADD:
printf("Enter\r\n"
"1 to add in head\r\n"
"2 to add in tail\r\n"
"3 to add in mid\r\n");
scanf_s("%d", &iNum);
printf("Enter the element to be added: ");
scanf_s("%d", &iEle);
if (iNum == ADD_IN_MID)
{
printf("Enter the element before the one to be added: ");
scanf_s("%d", &iLoc);
}
addToList(iEle, iLoc, ptHead, iNum);
break;
case MENU_ALTER:
printf("Enter\r\n"
"1 to alter one\r\n"
"2 to alter all\r\n");
scanf_s("%d", &iNum);
printf("Enter the Pre element: ");
scanf_s("%d", &iLoc);
printf("Enter the new element: ");
scanf_s("%d", &iEle);
alterInList(iEle, iLoc, ptHead, iNum);
break;
case MENU_DELETE:
printf("Enter\r\n"
"1 to delete in one\r\n"
"2 to delete in all\r\n");
scanf_s("%d", &iNum);
printf("Enter the element: ");
scanf_s("%d", &iEle);
deleteFromList(iEle, ptHead, iNum);
break;
case MENU_PRINT:
printList(ptHead);
break;
}
return 0;
}
int main(void)
{
PT_List ptHead;
ptHead = createList();
if (!ptHead)
return -1;
while (menu(ptHead) >= 0);
return 0;
}
#endif