c语言中删除有序数组中重复元素,去除有序列表中的重复元素
2014-10-27 09:13:00更新
你仔細研究一下我寫的 testAsignPoint 和 testAsignPointAgain 函數就會明白為什么你的二級指針無效了。
還是那句話,你要記住,指針就是一個變量,存的是32位數據,記住這個才能真正的理解指針。
另外 @pezy 說有內存漏洞,實際上我的完整代碼是下面的,我大學是acm出身的,只有初期才使用真正的指針,后期acm中都是使用數組代表指針的,這才是真正的升華,同樣存的是地址,這時只不過地址是數組的下標罷了。
當然,下面的代碼我沒有使用數組代替指針,不然就沒法用指針來講了。
最后,我加上我的測試的完整代碼:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
#ifdef __int64
typedef __int64 LL;
#else
typedef long long LL;
#endif
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(NULL) {}
ListNode(int x, ListNode *next) : val(x), next(next) {}
ListNode():next(NULL) {}
} str[100];
ListNode *deleteDuplicates(ListNode *head) {
while(head && head->next) {
if(head->val==head->next->val) {
head->next = head->next->next;
} else {
head = head->next;
}
}
return head;
}
ListNode *oldDeleteDuplicates(ListNode *head) {
ListNode **pcur=&head; //取得 head 變量的
if(head==NULL||head->next==NULL) {//特判是不是沒有元素或者只有一個元素
return head;
}
/*
這個時候 head 是 one 的地址。
pcur 是 head 的地址。
*pcur 就代表 head 了,即 one
(*pcur)->nex 指向 two,所以不結束循環,且比較相等了
所以你給 *pcur 賦值,也就是給 head 賦值。
此時 *pcur 就指向 two 了。
*/
while((*pcur)->next!=NULL) {
if((*pcur)->val==(*pcur)->next->val) {
*pcur=(*pcur)->next;
// (*pcur)->next =((*pcur)->next->next);
} else {
pcur=&((*pcur)->next);
}
}
return head;
}
void testAsignPoint(ListNode *head) {
printf(" asign begin=%0x\n",head);
head = head->next;
printf(" asign begin=%0x\n",head);
}
void myprintf(ListNode* head) {
while(head != NULL) {
printf("%d ", head->val);
head=head->next;
}
printf("\n");
}
void testAsignPointAgain(unsigned int addr){
printf(" asign begin=%0x\n",addr);
addr = (unsigned int)((ListNode *)addr)->next;//28fef8
printf(" asign begin=%0x\n",addr);
}
void test(ListNode* ptest) {
printf("ptest begin=%0x\n",ptest);//28fef0
testAsignPoint(ptest);
printf("one ptest =%0x\n",ptest);//28fef0
printf("same as before code");
testAsignPointAgain((unsigned int)(ptest));
printf("one ptest =%0x\n",ptest);//28fef0
printf("ptest=%0x\n",ptest);
myprintf(ptest);
oldDeleteDuplicates(ptest);
myprintf(ptest);
deleteDuplicates(ptest);
printf("ptest=%0x\n",ptest);
myprintf(ptest);
}
void testSample(){
ListNode three(1, NULL);
ListNode two(0, &three);
ListNode one(0, &two);
test(&one);
}
int main() {
int n = 10;
for(int i=0; i
str[i].val = i/2;
str[i].next = &str[i+1];
}
str[n].val = n/2;
str[n].next = NULL;
printf("deleteDuplicates begin\n");
myprintf(str);
deleteDuplicates(&str[0]);
myprintf(str);
printf("deleteDuplicates end\n");
printf("\n");
printf("test Asign Point begin\n");
testSample();
printf("test Asign Point begin\n");
return 0;
}
分割線
更新時間:2014-10-26 15:28
先告訴你我對指針的定義:指針可以理解為一個類型,或者一類類型。和int,double,自定義類型等是沒有區別的。
實際上最簡潔的代碼是下面的樣子
ListNode *deleteDuplicates(ListNode *head) {
while(head && head->next) {
if(head->val==head->next->val) {
head->next = head->next->next;
} else {
head = head->next;
}
}
return head;
}
之所以你使用錯誤,根本原因是由于你錯誤的理解了指針:以指針為參數,只會修改指針的值,如果對指針變量修改,原來那個指針是不受影響的。
前端時間剛好我看了一本書《重構~改善既有代碼的設計》,里面的一個重構目標就是對于串的指針全部改成 final, java 中沒有指針,但是傳的對象全部是引用,如果添加為 final 就是不能給變量賦值,但是可以修改對象里面的值。c 語言的 const 也有這個漏洞,算是hack做法吧,不推薦。
扯遠了,回頭來看你的問題,不理解的時候最簡單的方法就是自己模擬一下。
假設有鏈表有三個元素
ListNode three(1, NULL);
ListNode two(0, &three);
ListNode one(0, &two);
結構是這個樣子:one -> two -> three
為了傳入指針,我們事先一個函數吧。
void test(ListNode* pTest){
printf("head=%0x\n",pTest);
deleteDuplicates(pTest);
printf("head=%0x\n",pTest);
}
test(&one);
對于這個 pTest以參數形式傳給deleteDuplicates,由于不是引用,所以傳進去的是一個32位數據,可以稱為地址。
接下來我們模擬一下你的函數:
ListNode *oldDeleteDuplicates(ListNode *head) {
ListNode **pcur=&head; //取得 head 變量的
if(head==NULL||head->next==NULL) {//特判是不是沒有元素或者只有一個元素
return head;
}
/*
這個時候 head 和 pTest 的值一樣,都是 one 的地址。
pcur 是 head 的地址。
*pcur 就代表 head 了,即 one
(*pcur)->next 指向 two,所以不結束循環,且比較相等了
所以你給 *pcur 賦值,也就是給 head 賦值。
此時 *pcur 就指向 two 了。
而此時 pTest 還是指向 one 的,而one還是指向two的。
模擬至此,下面再看看為什么是這個樣子。
*/
while((*pcur)->next!=NULL) {
if((*pcur)->val==(*pcur)->next->val) {
*pcur=(*pcur)->next;
// (*pcur)->next =((*pcur)->next->next);
} else {
pcur=&((*pcur)->next);
}
}
return head;
}
為什么 pTest 沒有改變呢?
我們再測試一下。
void testAsignPoint(ListNode *head) {
printf(" asign begin=%0x\n",head);
head = head->next;
printf(" asign begin=%0x\n",head);
}
void test(ListNode* ptest) {
printf("test begin=%0x\n",ptest);
testAsignPoint(ptest);
printf("test end =%0x\n",ptest);
}
test(&one);
輸出時下面的數據
test begin=28fef0
asign begin=28fef0
asign begin=28fef8
test end =28fef0
ptest 的地址是不會改變的,因為你傳的是 ptest 的值,而不是 ptest 的地址。
分割線
原始回答:
根據你的算法:*pcur=(*pcur)->next;得到一個結論: 當重復時,你刪除的是前一個
但是如果頭部重復的時候,你只是改變一下指針,這樣的算法肯定不能解決頭部問題的。
你需要改變算法為:當重復的時候,刪除后一個。
即使后面的你一定要使用你的那個算法,那頭部就只有特判然后使用 重復時刪除后面的 算法
刪除后一個的算法如下:
ListNode *deleteDuplicates(ListNode *head) {
ListNode **pcur=&head;
if(head==NULL||head->next==NULL) {
return head;
}
while((*pcur)->next!=NULL) {
if((*pcur)->val==(*pcur)->next->val) {
// *pcur=(*pcur)->next;
(*pcur)->next =((*pcur)->next->next);
} else {
pcur=&((*pcur)->next);
}
}
return head;
}
總結
以上是生活随笔為你收集整理的c语言中删除有序数组中重复元素,去除有序列表中的重复元素的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: linux怎么截图到windows(li
- 下一篇: android u盘检测工具,andro