1 //当只需要做查找操作的时候 最好的是用顺序表O(1) 2 //经常需要做插入和删除的时候 用链表,当然如果这个位置在表末尾,用顺序表也行 3 //当经常删除和插入的位置在表头或者中间的时候,顺序表要挪很多次 4 //空间上:链表要比顺序表消耗大 因为多了指针域 5 /*C++中用stl list就能用链表了 头文件是<list> 6 JAVA中用链表就是引入LinkedList 和ArrayList的使用方法一样 7 */ 8 9 /* 10 带头指针:第一个头结点就存放数据,但是有head pointer指向这个节点 11 带头结点:第一个头结点不存放数据,只是用来索引链表的起始位置 12 相比较: 13 head node 14 | 15 [ ] -> [ ] -> [ ] -> .... 16 17 带头结点的比带头指针的要多耗一个空间 18 19 20 head pointer 21 | 22 ?????? -> [ ] -> [ ] -> [ ] 23 带头指针在遍历过程中会(可以)发生变化 24 而带头结点的不能改变指针域,只能改变头结点的指针域 25 */ 26 #include<cstdio> 27 #include<iostream> 28 #include<cstdlib> 29 30 using namespace std; 31 32 struct Node{ 33 int data; 34 struct Node* next; 35 }; 36 37 typedef struct Node* LList; 38 39 void init(struct Node **phead){ 40 *phead = NULL; 41 } 42 43 int getLength(struct Node* head){ 44 int len = 0; 45 while(head != NULL){ 46 len ++; 47 head = head->next;//并没有改变头指针 只是修改了head这个局部变量 48 } 49 50 return len; 51 } 52 53 void printList(struct Node* head){ 54 while(head!=NULL){ 55 printf("%d, ",head->data); 56 head = head->next;//并没有改变头指针 只是修改了head这个局部变量 57 } 58 printf("\n"); 59 } 60 61 struct Node* createNode(int x){ 62 struct Node* t; 63 //这里应该要加入一个判断剩余空间是否足够malloc 64 t = (struct Node*)malloc(sizeof(struct Node)); 65 t->next = NULL; 66 t->data = x; 67 return t; 68 } 69 70 //因为查找第k-1个点在insert和remove中都要用到 71 //我们在编程中应该尽量不要去复制代码 而是封装成函数 72 //尽管函数名叫findK,但是我们找的是第k-1个,所以函数传值传的是k-1 73 struct Node * findKth(struct Node* head, int k){ 74 int count = 1; 75 struct Node* p; 76 p = head; 77 while(p != NULL && count < k){ 78 p = p->next; 79 count++; 80 } 81 //p可能为空 但是无所谓 下面调用这个函数的地方也有判断语句 82 return p; 83 } 84 85 86 //** 指针的指针,存的是指针的地址 87 bool insert(struct Node** phead, int k, int x){ 88 if(k < 1){ 89 return false; 90 } 91 //在第一个点插入,要把头指针指向这个点 92 else if(k == 1){ 93 struct Node *t; 94 //注意createNode后,t->next = NULL 95 //假如这个链表原来不是个空表的话,原来的数据都会丢失 96 t = createNode(x); 97 //要把原先的点的next赋值给t才行 98 t->next = *phead; 99 *phead = t; 100 return true; 101 } 102 103 //在第一个点后面插入的情况 104 //一个个去遍历找到k-1的位置 如果k-1不存在那就没法插入了 105 //例如1 2 3 4,插在6是插不了,插在5就可以 106 struct Node * p;//存k-1的位置 107 /* 108 int count = 1;//用来计数 109 p = *phead; 110 //当循环判断条件里面的范围不确定的时候,先试着运行一下等下再修改也行 111 while(p!=NULL && count < k - 1){ 112 p = p->next; 113 count ++; 114 } 115 封装成了findKth 116 */ 117 //尽管函数名叫findK,但是我们找的是第k-1个,所以函数传值传的是k-1 118 p = findKth(*phead, k - 1); 119 120 if(p){ 121 struct Node* t; 122 //因为(struct Node*)malloc(sizeof(struct Node));要在很多地方用 123 //干脆就搞成一个函数算了 124 t = createNode(x); 125 t->next = p->next; 126 p->next = t; 127 return true; 128 } 129 else{// 1 2 3 4你要插入6,p会指向前一个,就是空的,就插不进去 130 return false; 131 } 132 } 133 134 bool removeNode(struct Node** phead, int k, int *px){ 135 //区分第一个节点和后面的节点 136 if(k < 0){ 137 return false; 138 } 139 if(k == 1){ 140 if(*phead != NULL){ 141 *px = (*phead)->data; 142 *phead = (*phead)->next; 143 return true; 144 } 145 //*phead为空的时候这个表是个空表 146 else return false; 147 148 } 149 else{ 150 struct Node *p; 151 p = findKth(*phead, k - 1); 152 if(p == NULL || p->next == NULL){ 153 //要删除第k个,当没有第k-1位置,或者k-1往下是空(就没有第k个,也是错) 154 return false; 155 } 156 struct Node* t; 157 t = p->next; 158 p->next = t->next; 159 *px = t->data; 160 free(t); 161 return true; 162 } 163 } 164 165 int main(){ 166 LList head;//头指针 167 //初始化 创建空链表 168 init(&head); 169 //遍历(打印 求表长) 170 int k = getLength(head); 171 //printf("%d\n",k); 测试 172 printList(head); 173 //int falg = insert(&head, 1, 11); 测试插入 174 insert(&head, 1, 11);//head表示哪个表,因为头指针可能会变,所以传head的地址;位置;元素数据 175 insert(&head, 1, 22); 176 insert(&head, 2, 33); 177 insert(&head, 4, 44); 178 insert(&head, 6, 55); 179 printList(head); 180 int x;//传入x的地址,用x来获取删除的点的数值 181 removeNode(&head, 1, &x);//删除第一个点的时候会改变头指针,所以传入地址 182 //printf("%d\n",x); 183 printList(head); 184 return 0; 185 }