数据结构之链表(C语言实现)
1 #include<stdio.h> 2 #include<malloc.h> 3 #include<stdlib.h> 4 typedef struct Node ///定义一个结点(结构体) 5 { 6 int data; ///数据域 7 struct Node * pNext;///指针域:一个结点的指针与指向的是下一个结点!而不是下一个结点的指针域,更不是下一个结点的数据域 8 }NODE,*PNODE; ///NODE等价于struct Node;PNODE等价于struct Node* 9 10 ///下面是对各种函数的声明 11 PNODE create_list(void); 12 void traverse_list(PNODE pHead); 13 int is_empty(PNODE pHead); 14 int length_list(PNODE pHead); 15 int sort_list(PNODE pHead); 16 int insert_list(PNODE pHead,int pos,int val); 17 int delet_list(PNODE pHead,int pos,int *pVal); 18 19 ///主函数 20 int main() 21 { 22 PNODE pHead=NULL; ///等价于struct Node *pHead = NULL; 23 pHead=create_list(); ///创建一个非循环单链表,并将该链表的地址赋给pHead 24 traverse_list(pHead); 25 printf("请输入插入元素的位置和插入的元素值:"); 26 int pos1,val1; 27 scanf("%d%d",&pos1,&val1); 28 insert_list(pHead,pos1,val1); 29 printf("插入后的链表:"); 30 traverse_list(pHead); 31 printf("请输入要删除的元素位置和元素的值:"); 32 int pos2,val2; 33 scanf("%d%d",&pos2,&val2); 34 delet_list(pHead,pos2,&val2); 35 printf("删除后的链表:"); 36 traverse_list(pHead); 37 printf("链表是否为空:"); 38 printf("%d\n",is_empty(pHead)); 39 printf("链表的长度:"); 40 printf("%d\n",length_list(pHead)); 41 sort_list(pHead); 42 printf("链表排序结果为:"); 43 traverse_list(pHead); 44 return 0; 45 } 46 47 PNODE create_list(void) ///创建链表 48 { 49 int len; ///存放有效结点的个数 50 int i; 51 int val; ///用来临时存放用户输入的结点的值 52 53 PNODE pHead=(PNODE)malloc(sizeof(NODE)); ///为结点动态分配内存 54 if(NULL==pHead) 55 { 56 printf("分配失败,程序终止!\n"); 57 exit(-1); 58 } 59 PNODE pTail=pHead; ///初始化头结点和尾结点,使尾结点指向头结点的位置,说明该链表没有有效结点 60 pTail->pNext=NULL; ///尾结点的尾指针指向为空,说明尾指针之后无结点 61 62 printf("请输入您需要生成的链表节点的个数:len="); 63 scanf("%d",&len); 64 65 for(i=0;i<len;i++) 66 { 67 printf("请输入第%d个节点的值:",i+1); 68 scanf("%d",&val); 69 70 PNODE pNew=(PNODE)malloc(sizeof(NODE));///生成了一个新结点 pNew,作为添加新结点的临时储存单元。 71 if(NULL==pNew) 72 { 73 printf("分配失败,程序终止!\n"); 74 exit(-1); 75 } 76 pNew->data=val; ///把输入的数据存在新结点的数据域 77 pTail->pNext=pNew; ///使链表原有的尾指针指向新结点 78 pNew->pNext=NULL; ///将新结点的尾指针指向置空(这跟尾指针初始化的操作一样,是在为下一步将pTail赋值为pNew做准备) 79 pTail=pNew; ///将pTail赋值为pNew,pNew结点成为了新的尾结点 80 } 81 return pHead; 82 } 83 84 void traverse_list(PNODE pHead) ///遍历链表并输出 85 { 86 PNODE p=pHead->pNext; 87 while(NULL!=p) 88 { 89 printf("%d ",p->data); 90 p=p->pNext; 91 } 92 printf("\n"); 93 } 94 95 int is_empty(PNODE pHead) ///判断链表是否为空(链表不存在满的状态!所以没有判断链表是否为满的函数) 96 { 97 if(NULL==pHead->pNext) ///当链表为空时,头结点与尾结点指向相同,所以头结点(可以看作尾结点)的指针指向为空 98 return 1; 99 else 100 return 0; 101 } 102 103 int length_list(PNODE pHead) ///计算链表长度 104 { 105 PNODE p=pHead->pNext; 106 int len=0; 107 while(NULL!=p) ///设置计数器,直到p为空时计数结束 108 { 109 len++; 110 p=p->pNext; 111 } 112 return len; 113 } 114 115 int sort_list(PNODE pHead) ///排序(这里使用的是简单的冒泡排序(排序问题不是该程序的重点,不再赘述),也可以用其他排序代码替换此函数内的代码) 116 { 117 int i,j,t; 118 int len=length_list(pHead); 119 PNODE p,q; 120 121 for(i=0,p=pHead->pNext;i<len-1;++i,p=p->pNext) 122 { 123 for(j=i+1,q=p->pNext;j<len;++j,q=q->pNext) 124 { 125 if(p->data>q->data) 126 { 127 t=p->data; 128 p->data=q->data; 129 q->data=t; 130 } 131 } 132 } 133 return 0; 134 } 135 136 ///插入和删除的本质是一样的,关键点在于:对某一个结点操作时,必须依靠它的前一个结点,依此类推。除非已经用新的变量名保存了该结点 137 int insert_list(PNODE pHead,int pos,int val) ///插入元素 138 { 139 int i=0; 140 PNODE p=pHead; 141 while(NULL!=p&&i<pos-1) 142 { 143 p=p->pNext; 144 ++i; 145 } 146 if(i>pos-1||NULL==p) 147 return 0; 148 PNODE pNew=(PNODE)malloc(sizeof(NODE)); 149 if(NULL==pNew) 150 { 151 printf("动态内存分配失败!\n"); 152 exit(-1); 153 } 154 ///注意以下四行代码 155 pNew->data=val;/// 156 PNODE q=p->pNext;/// 157 p->pNext=pNew;/// 158 pNew->pNext=q;/// 159 return 1; 160 } 161 162 int delet_list(PNODE pHead,int pos,int *pVal) ///删除元素 163 { 164 int i=0; 165 PNODE p=pHead; 166 while(NULL!=p->pNext&&i<pos-1) 167 { 168 p=p->pNext; 169 ++i; 170 } 171 if(i>pos-1||NULL==p->pNext) 172 return 0; 173 ///注意以下三行代码 174 PNODE q=p->pNext;/// 175 *pVal=q->data;/// 176 p->pNext=p->pNext->pNext;/// 177 free(q); 178 q=NULL; 179 return 1; 180 }
向代码最深处出发~!