c语言链表指向头指针,C语言单向链表操作总结(通过二级指针实现优化)

从【C和指针】这本书上看到在单向链表中插入节点时可以用一个二级指针来遍历,这个二级指针最初指向链表的头指针,随后的遍历过程中指向每个节点的pNext成员(pNext成员是指向下一个节点的指针),这样就可以将头指针看成一个空节点中的pNext成员,而不需要像使用一级指针那样将头指针作为一种特殊情况来考虑。也就是说使用二级指针后在链表的头部、中间、尾部插入节点的操作都可以看做同一种情况来处理,可以使用同一种操作方法,简化了插入函数。

类比到排序算法中,以插入排序为例,也可以使用二级指针来进行优化,当然由于链表实现的插入排序是直接将节点进行移动(不同于数组),所以每一次循环中是否有插入操作发生会产生两种不同的情况,需分开讨论,不过也只需加一个flag判断即可,具体在例程的注释中有体现,当然涉及较多的指针操作时,需要注意对NULL指针执行解引用操作会发生错误,但编译器不会报错(例如插入排序函数的最后一个if就是为了避免这样的错误)。

下面是例程:

#include

#include

typedef struct node{

int num;

struct node* pNext;

}Node;

#define SIZE sizeof(Node)

//

//创建一个链表并以输入为-1结束,返回链表头指针

//

Node* CreateList(){

int val;

Node *pHead, *pNode, *pTail;

pHead = pNode = pTail = NULL;

scanf("%d", &val);

while(val != -1){

pNode = (Node*)malloc(SIZE);

pNode->num = val;

pNode->pNext = NULL;

if(pHead == NULL)

pHead = pNode;

else

pTail->pNext = pNode;

pTail = pNode;

scanf("%d", &val);

}

return pHead;

}

//

//输出整个链表

//

void OutputList(Node *pHead){

while(pHead != NULL){

printf("%d ", pHead->num);

pHead = pHead->pNext;

}

printf("\b");

printf("\n");

}

//

//计算链表长度并返回节点数

//

int ListLength(Node *pHead){

int count = 0;

while(pHead != NULL){

count++;

pHead = pHead->pNext;

}

return count;

}

//

//删除所有值为val的节点并返回值1,若无值为val的节点则返回0

//

int DeleteNode(Node **ppHead, int val){

Node **ppNode = ppHead;

Node *pNode;

int flag = 0;

while(*ppNode != NULL)

if((*ppNode)->num == val){

pNode = *ppNode;

*ppNode = (*ppNode)->pNext;

free(pNode);

flag = 1;

}

else

ppNode = &((*ppNode)->pNext);

return flag;

}

//

//在链表第index个节点前插入值为val的节点并返回1,

//若链表长度不足index+1则返回0

//

int InsertNode(Node **ppHead, int val, int index){

Node **ppNode = ppHead;

Node *pNode;

int i;

//判断是否超出数列范围,其中需考虑包括数列末尾位置

if(ListLength(*ppHead) < index - 1)

return 0;

for(i = 1; i < index; i++)//找到插入位置

ppNode = &((*ppNode)->pNext);

pNode = (Node*)malloc(SIZE);

pNode->num = val;

pNode->pNext = *ppNode;

*ppNode = pNode;

return 1;

}

//

//升序插入排序

//

void InsertSort(Node **ppHead){

Node **ppNode = &((*ppHead)->pNext), **ppCursor;

Node *pNode;

//标记是否有插入发生

int flag;

while(*ppNode != NULL){

//每次循环均从头开始寻找插入位置

ppCursor = ppHead;

flag = 0;

while(ppCursor != ppNode)

if((*ppCursor)->num >= (*ppNode)->num){

//用一中间变量pNode指向需要被插入到前面已排序好的数列中的节点

pNode = *ppNode;

*ppNode = (*ppNode)->pNext;

pNode->pNext = *ppCursor;//插入节点

*ppCursor = pNode;

//*ppNode指向的节点被插入到前面已排序好的数列中

//则循环末尾无需移动ppNode即可进行下一节点的插入操作

flag = 1;

break;

}

else

ppCursor = &((*ppCursor)->pNext);

//*ppNode指向的节点没有被插入到前面已排序好的数列中

//则需使ppNode指向下一个节点的pNext成员

if(*ppNode != NULL&&flag == 0)

ppNode = &((*ppNode)->pNext);

}

}

//

//生成倒序链表

//

Node* ReverseList(Node *pHead){

Node *rpHead = NULL, *pNode;

while(pHead != NULL){

pNode = (Node*)malloc(SIZE);

pNode->num = pHead->num;

pNode->pNext = rpHead;

rpHead = pNode;

pHead = pHead->pNext;

}

return rpHead;

}

int main(void){

Node *ptrHead, *rPtrHead;

int DeleteNumber, InsertNumber, Index;

printf("输入一个数列并以-1结束\n");

ptrHead = CreateList();

printf("输入要删除的数\n");

scanf("%d", &DeleteNumber);

if(DeleteNode(&ptrHead, DeleteNumber))

OutputList(ptrHead);

else

printf("Delete Failure!\n");

printf("输入要插入的数及将要插入该数在第几节点前\n");

scanf("%d%d", &InsertNumber, &Index);

if(InsertNode(&ptrHead, InsertNumber, Index))

OutputList(ptrHead);

else

printf("Insert Failure!\n");

printf("倒序输出原链表\n");

rPtrHead = ReverseList(ptrHead);

OutputList(rPtrHead);

printf("进行插入排序\n");

InsertSort(&ptrHead);

OutputList(ptrHead);

}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值