1 #include <stdio.h> 2 int main(void) 3 { 4 //定义节点 5 typedef struct node 6 { 7 datatype data; 8 struct node *next; 9 }LNode,*LinkList; //LNode是节点类型,LinkList是指向LNode类型节点的指针类型 10 LinkList H; //定义头指针变量 11 12 //建立单链表(时间复杂度均为O(n)) 13 //逆序建立单链表(头插法) 14 LinkList Creath_LinkList() 15 { 16 Linklist L = NULL; //空表 17 LNode *s; 18 int e; //设数据元素的类型为int 19 scanf("%d", &e); 20 while(e != flag) //flag为设置的线性表数据元素结束标志 21 { 22 s = malloc(sizeof(LNode)); 23 s->data = e; 24 s->next = L; 25 L = s; 26 scanf("%d", &e); 27 } 28 return L; 29 } 30 //顺序建立单链表(尾插法) 31 LinkList Creatr_LinkList() 32 { 33 LinkList L = NULL; 34 LNode *s, *r = NULL; 35 int e; //设数据元素的类型为int 36 scanf("%d", &e); 37 while(e != flag) //flag为设置的线性表数据元素结束标志 38 { 39 s = malloc(sizeof(LNode)); 40 s->data = e; 41 if(L == NULL) L = s;//插入的节点是第一个节点 42 else r->next = s; //插入的节点是其他节点 43 r = s; //r恒指向新的节点 44 scanf("%d", &e); 45 } 46 if(r != NULL) r->next = NULL;//对于非空表,尾部节点的指针于置为空指针 47 return L; 48 } 49 50 //求表长(时间复杂度均为O(n)) 51 //设L是不带头节点的单链表 52 int length_LinkList1(LinkList L) 53 { 54 LNode *p = L; 55 int i; //i是计数器 56 if(p == NULL) return 0; //空表的情况 57 i = 1; //在非空表的情况下,p所指的是第一个节点 58 while(P->next) 59 { 60 p = p->next; i++; 61 } 62 return i; 63 } 64 //设L是带头节点的单链表(引入头节点概念,在后面的算法中若不加额外说明则都认为单链表是带头节点的) 65 int length_LinkList2(LinkList L) 66 { 67 LNode *p = L; //p指向头节点 68 int i = 0; //i是计数器 69 while(P->next) 70 { 71 p = p->next; i++; //p所指的正是第i个节点 72 } 73 return i; 74 } 75 76 //查找操作(时间复杂度均为O(n)) 77 //按序号查找 78 LNode *Getc_LinkList(LinkList L, int i) //在单链表L中查找第i个节点,找到则返回其指针,否则返回空 79 { 80 LNode *p = L; //L为头节点 81 int j = 0; 82 while(p->next != NULL && j<i) 83 { 84 p = p->next; j++; 85 } 86 if(j == i) return p; 87 else return NULL; 88 } 89 //按值查找 90 LNode *Locate_LinkList(LinkList L,datatype e) //在单链表L中查找值为e的节点,找到后返回其指针,否则返回空 91 { 92 LNode *p = L->next; //L为头节点 93 while(p != NULL && p->data != e) 94 p = p->next; 95 return p; 96 } 97 98 //插入操作 99 //在某节点之后插入节点(将*s插入*p的后面,时间复杂度为O(1)) 100 s->next = p->next; 101 p->next = s; //这两条指令顺序不能改变,否则会使链表断开 102 //在某节点之前插入节点(将*s插入*p的前面,时间复杂度为O(n)) 103 q = L; 104 while(q->next != p) 105 q = q->next; //查找*p的直接前驱*q 106 s->next = q->next; 107 q->next = s; 108 //定位插入(把数据域值为e的节点插入链表中作为第i个节点,时间复杂度为O(n)) 109 int Insert_LinkList(LinkList L, int i, datatype e) //在链表的第i个位置上插入值为e的元素 110 { 111 LNode *p, *s; 112 p = Get_LinkList(L, i-1); //查找第(i-1)个节点 113 if(p == NULL) 114 { 115 printf("参数i错"); return 0; //第(i-1)个节点不存在,不能插入 116 } 117 else 118 { 119 s = malloc(sizeof(LNode)); //申请节点 120 s->data = e; 121 s->next = p->next; //新节点插入在第(i-1)个节点的后面 122 p->next = s; 123 return 1; 124 } 125 } 126 127 //删除操作 128 //删除指针指向单链表中的节点 129 //(1)删除*p(时间复杂度为O(n)) 130 q->next = p->next; //设查找到*p的直接前驱为*q 131 free(p); 132 //(2)删除*p的直接后继节点,假设其存在(时间复杂度为O(1)) 133 s = p->next; //设*p的直接后继节点为*s 134 p->next = s->next; 135 free(s); 136 //删除单链表L的第i个节点(时间复杂度为O(n)) 137 int Del_LinkList(LinkList L, int i) //删除单链表上L的第i个节点 138 { 139 LinkList p, s; 140 p = Get_LinkList(L, i-1); //查找第(i-1)个节点 141 if(p == NULL) 142 { 143 printf("第i个节点不存在"); return -1; 144 } 145 else 146 { 147 if(p->next == NULL) 148 { 149 printf("第i个节点不存在"); return 0; 150 } 151 else 152 { 153 s = p->next; //s指向第i个节点 154 p->next = s->next; //从链表中删除s 155 free(s); //释放s 156 return 1; 157 } 158 } 159 } 160 return 0; 161 }
说明:
1.顺序建立单链表
由于第一个节点加入时原链表为空,它作为链表的第一个节点是没有直接前驱节点的,所以它的地址就是整个链表的起始地址,该值需要放在链表的头指针变量中;而后面再插入的其他节点都有直接前驱节点,其地址只需放入直接前驱节点的指针域即可。
2.头节点
为了统一操作,在链表的头部加入一个特殊节点,即头节点;头节点的类型与数据节点的类型一致,标识链表的头指针变量L中存放的是头节点的地址,那么即使是空表,头指针L也不为空(其中存放着头节点的地址);将头节点看作链表第一个节点的直接前驱,那么链表的第一个节点也有直接前驱,则无须再对第一个节点进行额外操作;
头节点的加入使得“空表”和“非空表”的处理成为一致,其数据域无定义,指针域存放的是第一个数据节点的地址。
算法思路:
1.求表长
设一个指针变量p和计数器i,初始化后,如果p所指节点后面还有节点,p向后移动,计数器i同时加1,直至p指向表尾。可以从单链表不带头节点和带头节点两个角度出发来设计算法(注意:计算线性表的长度时不包括头节点)。
2.查找操作
1)按序号查找:从链表的第一个节点起,判断当前节点是否是第i个节点,若是,则返回该节点的指针,否则,根据指针域寻找下一个节点,直到表结束为止。若没有找到第i个节点,则返回空。
2)按值查找:从链表的第一个节点起,判断当前节点数据域的值是否等于e,若等于,则返回该节点的指针,否则,根据指针域寻找下一个节点,直到表结束为止。若表中没有节点数据域的值等于e,则返回空。
3.插入操作(定位插入)
(1)寻找第i个节点的直接前驱第(i-1)个节点,若存在,则继续第(2)步,否则结束;
(2)申请新节点,并为其数据域赋值为e;
(3)将新节点作为第(i-1)个节点的直接后继插入单链表中,结束。
4.删除操作(删除单链表L的第i个节点)
(1)寻找第(i-1)个节点;若存在,则继续第(2)步,否则结束;
(2)若存在第i个节点,则继续第(3)步,否则结束;
(3)删除第i个节点,结束。