數據結構學習筆記(七)鏈表算法題(續)

第一題

問題

有一個遞增非空單鏈表,設計一個算法刪除值域重複的結點。好比{1,1,2,3,3,3,4,4,7,7,7,9,9,9通過刪除後變成{1,2,3,4,7,9}。前端

解答

解法一:定義指針p指向起始結點。將p所指當前結點值域和其直接後繼結點值域比較。若是當前結點值域等於後繼結點值域,刪除後繼結點;不然p指向後繼結點,重複以上過程,直到p的後繼結點爲空。node

本題代碼以下:算法

void delsl1(LNode *&L) {  //L是指針且要改變所以用引用指針型
    LNode *p = L->next,*q;

    while(p->next! = NULL){

        if(p->data == p->next->data) {    //找到重複結點刪除之
            q = p->next;
            p->next = q->next;
            free(q);
        }
        else
            p=p->next;
    }
}

解法二:依次將原序列中每一個連續相等子序列的第一個元素移動到表的前端,將剩餘的
元素刪除便可,即下圖所示過程。數組

令p指向起始將結點。q從p的後繼結點開始掃描,q每來到一個新結點的時候進行檢測:當q->data等於p->data的時候,什麼也不作,q繼續日後走;當二者不相等的時候,p日後走一個位置,而後用q->data取代p->data。以後q繼續日後掃描,重複以上過程。當q爲空的時候,釋放從p以後的全部結點空間。設計

void delsl2(LNode *&L) {

    LNode *p = L->next,*q = L->next->next,*r;

    while(q != NULL){
        while(q != NULL&&q->data == p->data)
            q = q->next;
            if(q! = NULL) {
                p = p->next;
                p->data = q->data;
            }
        }

        q = p->next;
        p->next = NULL;

        while(q != NULL)  {
            r = q;
            q = q->next;
        }
    }
    free(r);
}

第二題

問題

設計一個算法刪除單鏈表L(有頭結點)中的一個最小值結點。指針

解答

用p從頭到尾掃描鏈表,pre指向*p結點的前驅,用minp保存值最小的結點指針,minpre指向minp的前驅。一邊掃描,一邊比較,將最小值結點放到minp中。code

代碼以下:內存

void delminnode(LNode *&L){
    LNode *pre = L, *p = pre->next, *minp = p, *minpre = pre;

    while(p != NULL) {    //查找最小值結點minp以及前驅結點minpre
        if(p->data < minp->data){
            minp = p;
            minpre = pre;
        }

        pre = p;
        p = p->next;
    }

    minpre->next = minp->next; //刪除*minp結點。
    free(minp);
}

第三題

問題

有一個線性表,採用帶頭結點的單鏈表L來存儲。設計一個算法將其逆置。要求不能創建新結點,只能經過表中已有結點的從新組合來完成。it

解答

在前邊講過的算法基礎中,提到過關與逆序的問題,那就是鏈表創建的頭插法。頭插法完成後,鏈表中的元素順序和原數組中元素的順序相反。這裏咱們能夠將L中的元素做爲逆轉後L的元素來源,即將L->next設置爲空,而後將頭結點後的一串結點用頭插法逐個插入L中,這樣新的L中的元素順序正好是逆序的。基礎

代碼以下:

void Reversel(LNode *&L) {
    LNode *p = L->next,*q;
    L->next = NULL;
    while(p != NULL) {  //p結點始終指向舊的鏈表的開始結點。
        q = p->next; //q結點做爲輔助結點來記錄p的直接後繼結點的位置。
        p->next = L->next; //將p所指結點插入新的鏈表中。
        L->next = p;
        p = q; 
        //由於後繼結點已經存入q中,所以p仍然能夠找到後繼
        (即此時的新開始結點)。
    }
}

第四題

問題

設計一個算法將一個頭結點爲A的單鏈表(其數據域爲整數)分解成兩個單鏈表A

解答

用指針p從頭到尾掃描A鏈表,當發現結點data域爲偶數的結點則取下,插入鏈表B中。要用頭插法是用尾插法呢,由於題目要求保持原來數據元素的相對順序,因此要用尾插法來創建B鏈表。

代碼以下:

void split2(LNode *&A,LNode *&B) {
    LNode *p, *q, *r;
    B = (LNode*)malloc(sizeof(LNode)); //申請鏈表B的頭結點
    B->next = NULL;
    //每申請一個新結點的時候,將其指針域next設置爲NULL是個好習慣,這樣能夠避免不少因鏈表的終端結點忘記置NULL而產生的錯誤。

    r = B;
    p = A;

    while(p->next != NULL) { 
        //p始終指向當前被判斷結點的前驅結點,這和刪除結點相似,由於取下一個結點,就是刪除一個結點,只是不釋放這個結點的內存空間而已。

        if(p->next->data%2 == 0) {  //判斷結點的data域是否爲偶數,是則從鏈表中取下
            q = p->next;  //q指向要從鏈表中取下的結點
            p->next = q->next;    //從鏈表中取下這個結點
            q->next = NULL;
            r->next = q;
            r = q;
        }

        p = p->next;   //p後移一個位置,即開始檢查下一個結點。
    }
}
相關文章
相關標籤/搜索