8-15主要复习 1.运算符优先级整体记忆 2.排序算法
一、運算符優先級
優先級【高到低】:
第一級:() 【】 -> .
圓括號【()】、下標運算符【[]】、分量運算符的指向結構體成員運算符【->】、結構體成員運算符【.】
第二級:! ~ ++ -- - (int..) * & sizeof
邏輯非運算符【!】、按位取反運算符【~】、自增自減運算符【++?--】、負號運算符【-】、類型轉換運算符【(類型)】、指針運算符和取地址運算符【*和&】、長度運算符【sizeof】
第三級:乘法運算符【*】、除法運算符【/】、取余運算符【%】
第四級:加法運算符【+】、減法運算符【-】
第五級:左移動運算符【<<】、右移動運算符【>>】
第六級:關系運算符【<?>?<=?>=?】
第七級:等于運算符【==】、不等于運算符【!=】
第八級:按位與運算符【&】
第九級:按位異或運算符【^】
第十級:按位或運算符【|】
第十一級:邏輯與運算符【&&】
第十二級:邏輯或運算符【||】
第十三級:條件運算符【?:】
第十四級:賦值運算符【=?+=?-=?*=?/=?%=?>>=?<<.=?&=?|=?^=】
第十五級:逗號運算符【,】
?
?
二、排序相關知識點:
?
穩定排序與不穩定排序:
假設 Ri = Rj ,且排序前序列中 Ri 領先于 Rj ;
若在排序后的序列中 Ri 仍領先于 Rj ,則稱排序方法是穩定的。
若在排序后的序列中 Rj 仍領先于 Ri ,則稱排序方法是不穩定的。
?
例:序列 ??3 ???15 ????8 ????8 ????6 ????9
?
若排序后得 ??3 ????6 ?????8 ????8 ????9 ???15 ????????穩定的
若排序后得 ??3 ????6 ?????8 ????8 ????9 ???15 ????????不穩定的
?
內部排序: 指的是待排序記錄存放在計算機隨機存儲器中進行的排序過程。
外部排序: 指的是待排序記錄的數量很大,以致內存一次不能容納全部記錄,在排序過程中尚需對外存進行訪問的排序過程。
?
排序分類:
?????插入排序
直接插入排序 ?希爾排序
?交換排序
冒泡排序 ?快速排序
?選擇排序
簡單選擇排序 ?堆排序
?歸并排序
?基數排序
?
1.插入排序:
#include <stdio.h>void InsertSort(int par_array[], int array_size) {int i, j;int temp;for (i = 1; i < array_size; i++)// 從第二個開始 一個循環中 新加入的數去與前面的排好序的數比較 比前一個小 就不斷往前挪 相等或者大于了 那就結束了(穩定{temp = par_array[i];for (j = i - 1; j >= 0; j--){if (temp < par_array[j]){par_array[j + 1] = par_array[j];}else{break;}}par_array[j + 1] = temp;//temp向后挪一個 即加入后面的新元素} }int main() {int i = 0;int a[] = {3, 5, 2, 1, 9, 0, 6, 4, 7, 8};int length = sizeof(a) / sizeof(a[0]);InsertSort(a, length);for (i = 0; i < length; i++){printf("%d ", a[i]);}printf("\n");return 0; }2.希爾排序
#include <stdio.h>void ShellSort(int array[], int length) {int i, j;int h;int temp;for (h = length / 2; h > 0; h = h / 2)//對輸入的數組大小 取半(取半后的大小就是步長 以此步長進行兩個兩個數的比較) 直到最后為0為止{for (i = h; i < length; i++){temp = array[i];for (j = i - h; j >= 0; j -=h)//這里j 因為 i++ 所以j 也會++ 步長就是上面計算的{if (temp < array[j]){array[j + h] = array[j];}else{break;}}array[j + h] = temp;}} }int main() {int i = 0;int a[] = {0, 5, 2, 4, 3, 1, 7, 6, 8, 9};int length = sizeof (a) / sizeof(a[0]);ShellSort(a, length);for (i = 0; i < length; i++){printf("%d ", a[i]);}printf("\n");return 0;}3.冒泡排序
大家都會就不列了
4.快速排序
#include "stdio.h" void find_frst(int *s,int left,int right) {int i=left,j=right,temp; //(1)初始化i、j if(left>=right) return ;temp=s[i]; //(2)以第一個數組為比較值,保存到temp中 while(i<j){ while(j>i&&s[j]>=temp) //(3)j--,找小值 j--;s[i]= s[j]; //保存小值,到s[i]上 while(i<j&&s[i]<=temp) //(4)i++,找大值 i++;s[j--]=s[i]; //保存大值 到s[j]上 }s[i]=temp; //(5)將比較值放在s[i]上 /*(6)拆分成兩個數組 s[0,i-1]、s[i+1,n-1]又開始排序 */find_frst(s,left,i-1); //左find_frst(s,i+1,right); //右 } int main() {int i=0,s[100],n;scanf("%d",&n); //輸入數組長度for(i=0;i<n;i++)scanf("%d",&s[i]); find_frst(s,0,n-1); for(i=0;i<n;i++)printf("%d ",s[i]); //打印printf("\n"); }5.簡單選擇排序
#include <stdio.h>void SelectSort(int *a, int n) {int i, j;int temp = 0;int flag = 0;for (i = 0; i < n - 1; i++){temp = a[i];flag = i;for (j = i + 1; j < n; j++){if (a[j] < temp){temp = a[j];flag = j;}}if (flag != i){a[flag] = a[i];a[i] = temp;}} }int main() {int i = 0;int a[] = {5, 4, 3, 6, 1, 9, 7, 0, 2, 8};int length = sizeof(a) / sizeof(a[0]);SelectSort(a, length);for (i = 0; i < length; i++){printf("%d ", a[i]);}printf("\n");return 0; }6.后面慢慢加上來
?
?
?
3.三次握手四次揮手
1. 序列號seq
占4個字節,用來標記數據段的順序,TCP把連接中發送的所有數據字節都編上一個序號,第一個字節的編號由本地隨機產生,給字節編上序號后,就給每一個報文段指派一個序號,序列號seq就是這個報文段中的第一個字節的數據編號。
2. 確認號ack
占4個字節,期待收到對方下一個報文段的第一個數據字節的序號,序列號表示報文段攜帶數據的第一個字節的編號,而確認號指的是期望接受到下一個字節的編號,因此擋墻報文段最后一個字節的編號+1即是確認號。
3. 確認ACK
占1個比特位,僅當ACK=1,確認號字段才有效。ACK=0,確認號無效。
4. 同步SYN
連接建立時用于同步序號。當SYN=1,ACK=0表示:這是一個連接請求報文段。若同意連接,則在響應報文段中使用SYN=1,ACK=1.因此,SYN=1表示這是一個連接請求,或連接接收報文,SYN這個標志位只有在TCP建立連接才會被置為1,握手完成后SYN標志位被置為0.
5. 終止FIN
用來釋放一個
TCP三次握手以及四次揮手的過程
三次握手的過程
step1:第一次握手
建立連接時,客戶端發送SYN包到服務器,其中包含客戶端的初始序號seq=x,并進入SYN_SENT狀態,等待服務器確認。(其中,SYN=1,ACK=0,表示這是一個TCP連接請求數據報文;序號seq=x,表明傳輸數據時的第一個數據字節的序號是x)。
step2:第二次握手
服務器收到請求后,必須確認客戶的數據包。同時自己也發送一個SYN包,即SYN+ACK包,此時服務器進入SYN_RECV狀態。(其中確認報文段中,標識位SYN=1,ACK=1,表示這是一個TCP連接響應數據報文,并含服務端的初始序號seq(服務器)=y,以及服務器對客戶端初始序號的確認號ack(服務器)=seq(客戶端)+1=x+1)。
step3:第三次握手
客戶端收到服務器的SYN+ACK包,向服務器發送一個序列號(seq=x+1),確認號為ack(客戶端)=y+1,此包發送完畢,客戶端和服務器進入ESTAB_LISHED(TCP連接成功)狀態,完成三次握手。
未連接隊列
在三次握手協議中,服務器維護一個未連接隊列,該隊列為每個客戶端的SYN包(syn=j)開設一個條目,該條目表明服務器已收到SYN包,并向客戶發出確認,正在等待客戶的確認包時,刪除該條目,服務器進入ESTAB_LISHED狀態。
常見面試題:
1.為什么需要三次握手,兩次不可以嗎?或者四次、五次可以嗎??
我們來分析一種特殊情況,假設客戶端請求建立連接,發給服務器SYN包等待服務器確認,服務器收到確認后,如果是兩次握手,假設服務器給客戶端在第二次握手時發送數據,數據從服務器發出,服務器認為連接已經建立,但在發送數據的過程中數據丟失,客戶端認為連接沒有建立,會進行重傳。假設每次發送的數據一直在丟失,客戶端一直SYN,服務器就會產生多個無效連接,占用資源,這個時候服務器可能會掛掉。這個現象就是我們聽過的“SYN的洪水攻擊”。?
總結:第三次握手是為了防止:如果客戶端遲遲沒有收到服務器返回確認報文,這時會放棄連接,重新啟動一條連接請求,但問題是:服務器不知道客戶端沒有收到,所以他會收到兩個連接,浪費連接開銷。如果每次都是這樣,就會浪費多個連接開銷。
四次揮手過程(關閉客戶端到服務器的連接)
step1:第一次揮手
首先,客戶端發送一個FIN,用來關閉客戶端到服務器的數據傳送,然后等待服務器的確認。其中終止標志位FIN=1,序列號seq=u。
step2:第二次揮手
服務器收到這個FIN,它發送一個ACK,確認ack為收到的序號加一。
step3:第三次揮手
關閉服務器到客戶端的連接,發送一個FIN給客戶端。
step4:第四次揮手
客戶端收到FIN后,并發回一個ACK報文確認,并將確認序號seq設置為收到序號加一。首先進行關閉的一方將執行主動關閉,而另一方執行被動關閉。
客戶端發送FIN后,進入終止等待狀態,服務器收到客戶端連接釋放報文段后,就立即給客戶端發送確認,服務器就進入CLOSE_WAIT狀態,此時TCP服務器進程就通知高層應用進程,因而從客戶端到服務器的連接就釋放了。此時是“半關閉狀態”,即客戶端不可以發送給服務器,服務器可以發送給客戶端。?
此時,如果服務器沒有數據報發送給客戶端,其應用程序就通知TCP釋放連接,然后發送給客戶端連接釋放數據報,并等待確認。客戶端發送確認后,進入TIME_WAIT狀態,但是此時TCP連接還沒有釋放,然后經過等待計時器設置的2MSL后,才進入到CLOSE狀態。
2.為什么需要2MSL時間??
首先,MSL即Maximum Segment Lifetime,就是最大報文生存時間,是任何報文在網絡上的存在的最長時間,超過這個時間報文將被丟棄。《TCP/IP詳解》中是這樣描述的:MSL是任何報文段被丟棄前在網絡內的最長時間。RFC 793中規定MSL為2分鐘,實際應用中常用的是30秒、1分鐘、2分鐘等。
TCP的TIME_WAIT需要等待2MSL,當TCP的一端發起主動關閉,三次揮手完成后發送第四次揮手的ACK包后就進入這個狀態,等待2MSL時間主要目的是:防止最后一個ACK包對方沒有收到,那么對方在超時后將重發第三次握手的FIN包,主動關閉端接到重發的FIN包后可以再發一個ACK應答包。在TIME_WAIT狀態時兩端的端口不能使用,要等到2MSL時間結束才可以繼續使用。當連接處于2MSL等待階段時任何遲到的報文段都將被丟棄。
總結:?
(1)為了保證客戶端發送的最后一個ACK報文段能夠到達服務器。即最后一個確認報文可能丟失,服務器會超時重傳,然后客戶端再一次確認,同時啟動2MSL計時器。如果沒有等待時間,發送完確認報文段就立即釋放連接的話,服務器就無法重傳,因此也就收不到確認,就無法按步驟進入CLOSE狀態,即必須收到確認才能close。?
(2)防止已經失效的連接請求報文出現在連接中。經過2MSL,在這個連續持續的時間內,產生的所有報文段就可以都從網絡消失。
?
?
?
?
?
總結
以上是生活随笔為你收集整理的8-15主要复习 1.运算符优先级整体记忆 2.排序算法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于nanopi的即时通讯系统
- 下一篇: qt初学者 第一个小程序 小界面